diff --git a/.gitignore b/.gitignore index e31d6e1..d4e001b 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ venowm_shell_plugin.so test_split logmsg +venowm diff --git a/backend.h b/backend.h index 0eb75d2..391c9a2 100644 --- a/backend.h +++ b/backend.h @@ -7,7 +7,6 @@ /* don't like the #define strategy, there is no way to say that a struct of one name just refers to a struct of another name. */ -#include typedef struct be_screen_t be_screen_t; typedef struct be_window_t be_window_t; @@ -26,13 +25,8 @@ enum { MOD_SHIFT = 1 << 3, }; -typedef void (*be_key_handler_t)(struct weston_keyboard*, - const struct timespec*, - uint32_t, - void*); - int be_handle_key(backend_t *be, uint32_t mods, uint32_t key, - be_key_handler_t handler, void *data); + bool (*func)(backend_t*, void*), void *data); void be_screen_get_geometry(be_screen_t *be_screen, int32_t *x, int32_t *y, uint32_t *w, uint32_t *h); diff --git a/backend_wlroots.c b/backend_wlroots.c new file mode 100644 index 0000000..76b63ca --- /dev/null +++ b/backend_wlroots.c @@ -0,0 +1,1176 @@ +#define _POSIX_C_SOURCE 199309L +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "backend.h" +#include "venowm.h" +#include "logmsg.h" +#include "venowm_control.h" + +#include "venowm-shell-protocol.c" + +static void exec(const char *shcmd){ + logmsg("called exec\n"); + pid_t pid = fork(); + if(pid < 0){ + perror("fork"); + return; + } + if(pid == 0){ + // child + execl("/bin/sh", "/bin/sh", "-c", shcmd, NULL); + perror("execl"); + exit(127); + } + // parent continues with whatever it was doing + return; +} + +struct be_screen_t { + // cb_data is set by the frontend, we don't touch it. + void *cb_data; + backend_t *be; + struct wlr_output *output; + struct wl_list link; // backend_t.outputs + struct wl_listener output_destroyed_listener; + struct wl_listener frame_listener; + + struct wl_list windows; // be_window.link +}; + +struct be_window_t { + backend_t *be; + void *venowm_data; + // base wl_surface, the first thing to be created + struct wlr_surface *wlr_surface; + struct wl_listener wlr_surface_destroyed; + + // xdg_surface, extends a wl_surface + struct wlr_xdg_surface *xdg_surface; + bool mapped; // the application says if it's mapped or not + struct wl_listener xdg_destroyed; + struct wl_listener xdg_mapped; + struct wl_listener xdg_unmapped; + + // display properties + int32_t x; + int32_t y; + bool show; // we decide if the application is shown or not + struct wl_list link; // be_screen_t.windows +}; + +/* + KEY BINDING STRATEGY + + X keysyms are all within the 32-bit space with the some unused bits. We can + use this fact to make keybindings fit into a int32-keyed hash map of + (X keysym + modifier)s to function/data pairs. +*/ + +enum be_modifier_t { + // BE_MOD_ = 0x80000000 // skip the sign bit + BE_MOD_CTRL = 0x40000000, + BE_MOD_SHIFT = 0x20000000, + BE_MOD_ALT = 0x0F000000, + BE_MOD_SUPER = 0x04000000, + // BE_MOD_ = 0x02000000 + // BE_MOD_ = 0x01000000 + // BE_MOD_ = 0x00400000 + // BE_MOD_ = 0x00200000 + // BE_MOD_ = 0x00100000 +}; + +/* + Frankly, this seems like not a great idea but I think it's cool and if it + ever goes wrong it's easy enough to correct after the fact. +*/ + + +typedef struct { + // func should return "true" to consume the keypress + bool (*func)(backend_t*, void*); + void *data; +} keybinding_t; + +// custom hashtable mapping (X keysym + modifier)s to function/data pairs +KHASH_INIT(keymap, int32_t, keybinding_t, true, kh_int_hash_func, + kh_int_hash_equal); + +typedef struct { + khash_t(keymap) *bindings; + backend_t *be; + struct wl_list link; // backend_t.keymaps +} keymap_t; + +struct backend_t { + struct wl_display *display; + struct wl_event_loop *loop; + // the wayland backend + struct wlr_backend *wlr_backend; + struct wl_listener new_input_device; + // the wlr compositor + struct wlr_compositor *compositor; + struct wl_listener wlr_surface_created; + struct wl_listener compositor_destroyed_listener; + // xdg shell + struct wlr_xdg_shell *xdg_shell; + struct wl_listener xdg_shell_new_listener; + // xdg decorations + struct wlr_xdg_decoration_manager_v1 *decoration_mgr; + struct wl_listener decoration_new; + struct wl_listener decoration_mgr_destroy; + // kde decorations + struct wlr_server_decoration_manager *server_dec_mgr; + // venowm control stuff + venowm_control_t *vc; + // outputs + struct wlr_output_layout *output_layout; + struct wl_listener new_output_listener; + struct wl_list be_screens; + const char *socket; + // inputs + struct wlr_seat *seat; + uint32_t seat_caps; + struct wlr_cursor *cursor; + struct wlr_xcursor_manager *cursor_mgr; + struct wl_list pointers; // pointer_t.link + struct wl_list keyboards; // keyboard_t.link + + // keymaps + keymap_t *keymap_top; + struct wl_list keymaps; // keymap_t.link + + // for interacting with frontend + be_window_t *focus; +}; + +///// Backend Screen Functions + +static void be_screen_free(be_screen_t *be_screen){ + // call venowm's screen_destroy handler + handle_screen_destroy(be_screen->cb_data); + wl_list_remove(&be_screen->frame_listener.link); + wl_list_remove(&be_screen->output_destroyed_listener.link); + wl_list_remove(&be_screen->link); + // TODO: free view + // TODO: free surface + free(be_screen); +} + +static void handle_output_destroyed(struct wl_listener *l, void *data){ + (void)data; + be_screen_t *be_screen = wl_container_of( + l, be_screen, output_destroyed_listener); + backend_t *be = be_screen->be; + + wlr_output_layout_remove(be->output_layout, be_screen->output); + + be_screen_free(be_screen); + + // if that was the last screen, close venowm + if(be->be_screens.next == &be->be_screens){ + backend_stop(be); + } +} + +static void handle_frame(struct wl_listener *l, void *data){ + (void)data; + be_screen_t *be_screen = wl_container_of(l, be_screen, frame_listener); + struct wlr_output *o = be_screen->output; + + struct wlr_renderer *r = wlr_backend_get_renderer(o->backend); + + // prepare the output for rendering + if(!wlr_output_attach_render(o, NULL)){ + return; + } + wlr_renderer_begin(r, o->width, o->height); + + // render a blue background + float color[4] = {0.0, 0.0, 0.5, 1.0}; + wlr_renderer_clear(r, color); + + + // render all the windows on this screen + be_window_t *be_window; + wl_list_for_each(be_window, &be_screen->windows, link){ + // don't render windows not mapped or not being shown + if(!be_window->show || !be_window->mapped) + continue; + + struct wlr_surface *srfc = be_window->wlr_surface; + + // don't render surfaces with no buffer + if(!wlr_surface_has_buffer(srfc)) + continue; + + struct wlr_box render_box = { + .x = be_window->x, + .y = be_window->y, + .width = srfc->current.width, + .height = srfc->current.height, + }; + float mat[16]; + wlr_matrix_project_box((float*)&mat, &render_box, + srfc->current.transform, 0, (float*)&o->transform_matrix); + struct wlr_texture *texture = wlr_surface_get_texture(srfc); + wlr_render_texture_with_matrix(r, texture, (float*)&mat, 1.0f); + + struct timespec now; + clock_gettime(CLOCK_REALTIME, &now); + wlr_surface_send_frame_done(srfc, &now); + } + + // show software cursor if hardware cursor is not working + wlr_output_render_software_cursors(o, NULL); + + // TODO: set damage via wlr_output_set_damage() + // (there don't seem to be any examples) + + // done rendering, commit buffer + wlr_renderer_end(r); + wlr_output_commit(o); +} + +static be_screen_t *be_screen_new(backend_t *be, struct wlr_output *output){ + be_screen_t *be_screen = malloc(sizeof(*be_screen)); + if(!be_screen) return NULL; + *be_screen = (be_screen_t){0}; + + be_screen->be = be; + be_screen->output = output; + + // set mode, for backends with modes (the last mode is typically best) + if(!wl_list_empty(&output->modes)){ + struct wlr_output_mode *mode; + mode = wl_container_of(output->modes.prev, mode, link); + wlr_output_set_mode(output, mode); + } + + // add a blank background surface + // TODO: add a blank background + + // add a view to the background + // TODO: add a view to blank background + + wl_list_insert(be->be_screens.prev, &be_screen->link); + + be_screen->output_destroyed_listener.notify = handle_output_destroyed; + wl_signal_add(&output->events.destroy, + &be_screen->output_destroyed_listener); + + be_screen->frame_listener.notify = handle_frame; + wl_signal_add(&output->events.frame, &be_screen->frame_listener); + + // TODO: handle resize/move events? + + // call venowm's new screen handler and get cb_data + if(handle_screen_new(be_screen, &be_screen->cb_data)){ + goto cu_listeners; + } + + // create a global. Not honestly sure what this is good for. + wlr_output_create_global(output); + + // no windows on this screen yet + wl_list_init(&be_screen->windows); + + return be_screen; + +cu_listeners: + wl_list_remove(&be_screen->frame_listener.link); + wl_list_remove(&be_screen->output_destroyed_listener.link); + wl_list_remove(&be_screen->link); +//cu_view: + // TODO: free view +//cu_srfc: + // TODO: free surface +//cu_screen: + free(be_screen); + return NULL; +} + +static void handle_new_output(struct wl_listener *l, void *data){ + struct wlr_output *output = data; + backend_t *be = wl_container_of(l, be, new_output_listener); + + be_screen_t *be_screen = be_screen_new(be, output); + if(!be_screen) return; + + // how to handle more than one output? + wlr_output_layout_add(be->output_layout, output, 0, 0); + + // if this isn't the right scale, load the right scale + if(output->scale != 1.0){ + wlr_xcursor_manager_load(be->cursor_mgr, output->scale); + } +} + +///// End Backend Screen Functions + + +///// Input Functions + +void keymap_free(keymap_t *keymap){ + wl_list_remove(&keymap->link); + kh_destroy(keymap, keymap->bindings); + free(keymap); +} + +keymap_t *keymap_new(backend_t *be){ + // allocate keymap + keymap_t *keymap = malloc(sizeof(*keymap)); + if(!keymap) return NULL; + *keymap = (keymap_t){0}; + + // allocate hash table + keymap->bindings = kh_init(keymap); + if(!keymap->bindings) goto fail; + + // add binding to backend's list + keymap->be = be; + wl_list_insert(be->keymaps.prev, &keymap->link); + + return keymap; + +fail: + free(keymap); + return NULL; +} + +// returns 0 on success, -1 on error +int keymap_add_keybinding(keymap_t *keymap, int32_t modded_keysym, + bool (*func)(backend_t*, void*), void *data){ + // build a binding to be copied into the hashtable + keybinding_t binding = { + .func = func, + .data = data, + }; + + // get index + int ret; + khiter_t k = kh_put(keymap, keymap->bindings, modded_keysym, &ret); + if(ret < 0){ + return -1; + } + // write to index + kh_value(keymap->bindings, k) = binding; + + return 0; +} + +static const keybinding_t KEYBINDING_NONE = (keybinding_t){0}; + +// return KEYBINDING_NONE if there is no binding +keybinding_t keymap_get_keybinding(keymap_t *keymap, int32_t modded_keysym){ + // get index + khiter_t k = kh_get(keymap, keymap->bindings, modded_keysym); + // check if value is missing + int is_missing = (k == kh_end(keymap->bindings)); + if(is_missing){ + return KEYBINDING_NONE; + } + // return value + return kh_value(keymap->bindings, k); +} + +typedef struct { + backend_t *be; + struct wlr_input_device *device; + struct wl_listener key_listener; + struct wl_listener mod_listener; + struct wl_listener keyboard_destroyed; + struct wl_list link; // backend_t.keyboards +} keyboard_t; + +// return "true" to consume the keybinding +static bool keymap_filter_keysyms(keymap_t *keymap, uint32_t mods, + const xkb_keysym_t *keysyms, size_t nkeysyms){ + for(size_t i = 0; i < nkeysyms; i++){ + int32_t modded_keysym = keysyms[i]; + // capture modifiers we care about + if(mods & WLR_MODIFIER_SHIFT) modded_keysym |= BE_MOD_SHIFT; + if(mods & WLR_MODIFIER_CTRL) modded_keysym |= BE_MOD_CTRL; + if(mods & WLR_MODIFIER_ALT) modded_keysym |= BE_MOD_ALT; + if(mods & WLR_MODIFIER_MOD3) modded_keysym |= BE_MOD_SUPER; + + keybinding_t binding = keymap_get_keybinding(keymap, modded_keysym); + + if(!binding.func) continue; + + // call the first keybinding + return binding.func(keymap->be, binding.data); + } + return false; +} + +// return "true" to consume the keybinding +static bool keymap_filter_keycode(backend_t *be, struct wlr_keyboard *k, + xkb_keycode_t keycode){ + uint32_t modifiers; + const xkb_keysym_t *keysyms; + size_t nkeysyms; + + // try and read "translated" keysyms such as "s-bar" for "SUPER+SHIFT+\" + + // get modifiers + modifiers = wlr_keyboard_get_modifiers(k); + // see which modifiers are already consumed + xkb_mod_mask_t consumed = xkb_state_key_get_consumed_mods2(k->xkb_state, + keycode, XKB_CONSUMED_MODE_XKB); + modifiers &= ~consumed; + // get syms + nkeysyms = xkb_state_key_get_syms(k->xkb_state, keycode, &keysyms); + // check it against the keymap + if(keymap_filter_keysyms(be->keymap_top, modifiers, keysyms, nkeysyms)){ + return true; + } + + // try and read "raw" keysyms such as "s-shift+\" for "SUPER+SHIFT+\" + + modifiers = wlr_keyboard_get_modifiers(k); + xkb_layout_index_t layout_index = xkb_state_key_get_layout(k->xkb_state, + keycode); + nkeysyms = xkb_keymap_key_get_syms_by_level(k->keymap, keycode, + layout_index, 0, &keysyms); + if(keymap_filter_keysyms(be->keymap_top, modifiers, keysyms, nkeysyms)){ + return true; + } + + return false; +} + + +static void handle_key(struct wl_listener *l, void *data){ + keyboard_t *kbd = wl_container_of(l, kbd, key_listener); + struct wlr_event_keyboard_key *event = data; + struct wlr_keyboard *k = kbd->device->keyboard; + backend_t *be = kbd->be; + + xkb_keycode_t keycode = event->keycode + 8; + + if(event->state == WLR_KEY_PRESSED){ + if(keymap_filter_keycode(be, k, keycode)){ + return; + } + } + + // wlr_seat_set_keyboard() is a noop if this keyboard is already set + wlr_seat_set_keyboard(be->seat, kbd->device); + + // send key through seat + wlr_seat_keyboard_notify_key(be->seat, event->time_msec, event->keycode, + event->state); +} + +static void handle_modifier(struct wl_listener *l, void *data){ + (void)data; + keyboard_t *kbd = wl_container_of(l, kbd, mod_listener); + backend_t *be = kbd->be; + + // wlr_seat_set_keyboard() is a noop if this keyboard is already set + wlr_seat_set_keyboard(be->seat, kbd->device); + + // send modifier through seat + wlr_seat_keyboard_notify_modifiers(be->seat, + &kbd->device->keyboard->modifiers); +} + +static void keyboard_destroyed(struct wl_listener *l, void *data){ + keyboard_t *kbd = wl_container_of(l, kbd, keyboard_destroyed); + (void)data; + backend_t *be = kbd->be; + + // remove from backend list + wl_list_remove(&kbd->link); + + if(wl_list_empty(&be->keyboards) + && (be->seat_caps & WL_SEAT_CAPABILITY_KEYBOARD)){ + be->seat_caps &= ~WL_SEAT_CAPABILITY_KEYBOARD; + wlr_seat_set_capabilities(be->seat, be->seat_caps); + } +} + +static struct xkb_context *xkb_context = NULL; +static struct xkb_keymap *xkb_keymap = NULL; +static struct xkb_rule_names rules = {0}; + +static keyboard_t *keyboard_new(backend_t *be, + struct wlr_input_device *device){ + logmsg("new keyboard\n"); + keyboard_t *kbd = malloc(sizeof(*kbd)); + if(!kbd) return NULL; + *kbd = (keyboard_t){0}; + + device->data = kbd; + kbd->device = device; + kbd->be = be; + + + // // load a keyboard map (generated with `xkbcomp $DISPLAY xkb.dump`) + // if(!xkb_context){ + // xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + // FILE *f = fopen("xkb.dump", "r"); + // if(!f){ + // perror("fopen(xkb.dump)"); + // }else{ + // xkb_keymap = xkb_keymap_new_from_file( + // xkb_context, f, XKB_KEYMAP_FORMAT_TEXT_V1, 0); + // fclose(f); + // } + // } + + // use default xkb rules + if(!xkb_context){ + xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); + if(!xkb_context) goto fail; + } + if(!xkb_keymap){ + xkb_keymap = xkb_keymap_new_from_names( + xkb_context, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS); + if(!xkb_keymap) goto fail; + } + + wlr_keyboard_set_keymap(device->keyboard, xkb_keymap); + wlr_keyboard_set_repeat_info(device->keyboard, 40, 200); + + kbd->key_listener.notify = handle_key; + wl_signal_add(&device->keyboard->events.key, &kbd->key_listener); + + kbd->mod_listener.notify = handle_modifier; + wl_signal_add(&device->keyboard->events.modifiers, &kbd->mod_listener); + + kbd->keyboard_destroyed.notify = keyboard_destroyed; + wl_signal_add(&device->events.destroy, &kbd->keyboard_destroyed); + + // add to backend list + wl_list_insert(be->keyboards.prev, &kbd->link); + + if(!(be->seat_caps & WL_SEAT_CAPABILITY_KEYBOARD)){ + be->seat_caps |= WL_SEAT_CAPABILITY_KEYBOARD; + wlr_seat_set_capabilities(be->seat, be->seat_caps); + } + + wlr_seat_set_keyboard(kbd->be->seat, kbd->device); + + return kbd; + +fail: + free(kbd); + return NULL; +} + +typedef struct { + backend_t *be; + struct wlr_input_device *device; + struct wl_listener button_listener; + struct wl_listener motion_listener; + struct wl_listener motion_abs_listener; + struct wl_listener pointer_destroyed; + struct wl_list link; // backend_t.pointers +} pointer_t; + +static void handle_button(struct wl_listener *l, void *data){ + pointer_t *ptr = wl_container_of(l, ptr, button_listener); + struct wlr_event_mouse_button *event = data; + (void)event; (void)ptr; + // logmsg("button\n"); +} + +static void handle_motion(struct wl_listener *l, void *data){ + pointer_t *ptr = wl_container_of(l, ptr, motion_listener); + struct wlr_event_pointer_motion *event = data; + backend_t *be = ptr->be; + // logmsg("motion\n"); + + wlr_cursor_move(be->cursor, event->device, event->delta_x, event->delta_y); +} + +static void handle_motion_abs(struct wl_listener *l, void *data){ + pointer_t *ptr = wl_container_of(l, ptr, motion_abs_listener); + struct wlr_event_pointer_motion_absolute *event = data; + backend_t *be = ptr->be; + + wlr_xcursor_manager_set_cursor_image( + be->cursor_mgr, "left_ptr", be->cursor); + + double x; + double y; + wlr_cursor_absolute_to_layout_coords( + be->cursor, event->device, event->x, event->y, &x, &y); + + // logmsg("motion_abs (%.3f, %.3f) -> (%.3f, %.3f)\n", + // event->x, event->y, x, y); + + wlr_cursor_warp_closest(be->cursor, event->device, x, y); +} + +static void pointer_destroyed(struct wl_listener *l, void *data){ + pointer_t *ptr = wl_container_of(l, ptr, pointer_destroyed); + (void)data; + backend_t *be = ptr->be; + + // remove from backend list + wl_list_remove(&ptr->link); + + if(wl_list_empty(&be->pointers) + && (be->seat_caps & WL_SEAT_CAPABILITY_POINTER)){ + be->seat_caps &= ~WL_SEAT_CAPABILITY_POINTER; + wlr_seat_set_capabilities(be->seat, be->seat_caps); + } +} + +static pointer_t *pointer_new(backend_t *be, struct wlr_input_device *device){ + logmsg("new pointer\n"); + pointer_t *ptr = malloc(sizeof(*ptr)); + if(!ptr) return NULL; + *ptr = (pointer_t){0}; + + device->data = ptr; + ptr->device = device; + ptr->be = be; + + // listen to events + + ptr->button_listener.notify = handle_button; + wl_signal_add(&device->pointer->events.button, &ptr->button_listener); + + ptr->motion_listener.notify = handle_motion; + wl_signal_add(&device->pointer->events.motion, + &ptr->motion_listener); + + ptr->motion_abs_listener.notify = handle_motion_abs; + wl_signal_add(&device->pointer->events.motion_absolute, + &ptr->motion_abs_listener); + + ptr->pointer_destroyed.notify = pointer_destroyed; + wl_signal_add(&device->events.destroy, &ptr->pointer_destroyed); + + // add pointer to cursor + wlr_cursor_attach_input_device(be->cursor, device); + + // add to backend list + wl_list_insert(be->pointers.prev, &ptr->link); + + if(!(be->seat_caps & WL_SEAT_CAPABILITY_POINTER)){ + be->seat_caps |= WL_SEAT_CAPABILITY_POINTER; + wlr_seat_set_capabilities(be->seat, be->seat_caps); + } + + return ptr; +} + +static void handle_new_input_device(struct wl_listener *l, void *data){ + backend_t *be = wl_container_of(l, be, new_input_device); + struct wlr_input_device *device = data; + + switch(device->type){ + case WLR_INPUT_DEVICE_KEYBOARD: + logmsg("input: WLR_INPUT_DEVICE_KEYBOARD\n"); + keyboard_new(be, device); + break; + case WLR_INPUT_DEVICE_POINTER: + logmsg("input: WLR_INPUT_DEVICE_POINTER\n"); + pointer_new(be, device); + break; + case WLR_INPUT_DEVICE_TOUCH: + logmsg("input: WLR_INPUT_DEVICE_TOUCH\n"); + break; + case WLR_INPUT_DEVICE_TABLET_TOOL: + logmsg("input: WLR_INPUT_DEVICE_TABLET_TOOL\n"); + break; + case WLR_INPUT_DEVICE_TABLET_PAD: + logmsg("input: WLR_INPUT_DEVICE_TABLET_PAD\n"); + break; + case WLR_INPUT_DEVICE_SWITCH: + logmsg("input: WLR_INPUT_DEVICE_SWITCH\n"); + break; + } +} + +///// End Input Functions + + +///// Backend Window Functions + +static void be_window_free(be_window_t *be_window){ + // don't need to remove destroy handlers + free(be_window); +} + +static void handle_wlr_surface_destroyed(struct wl_listener *l, void *data){ + (void)data; + be_window_t *be_window; + be_window = wl_container_of(l, be_window, wlr_surface_destroyed); + be_window_free(be_window); + logmsg("freed window (handle_wlr_surface_destroyed)!\n"); +} + +static be_window_t *be_window_new(backend_t *be, + struct wlr_surface *wlr_surface){ + be_window_t *be_window = malloc(sizeof(*be_window)); + if(!be_window) return NULL; + *be_window = (be_window_t){0}; + + be_window->be = be; + be_window->wlr_surface = wlr_surface; + + // add destroy handler + be_window->wlr_surface_destroyed.notify = handle_wlr_surface_destroyed; + wl_signal_add(&wlr_surface->events.destroy, + &be_window->wlr_surface_destroyed); + + return be_window; +} + +static void handle_new_surface(struct wl_listener *l, void *data){ + struct wlr_surface *wlr_surface = data; + backend_t *be = wl_container_of(l, be, wlr_surface_created); + be_window_t *be_window = be_window_new(be, wlr_surface); + + logmsg("new wlr_surface! %p\n", wlr_surface); + + // we can't close the surface until it becomes an xdg_shell, so let NULL + // indicate that the surface is a total loser who deserves to be shutdown + + wlr_surface->data = be_window; +} + +static void handle_xdg_destroyed(struct wl_listener *l, void *data){ + be_window_t *be_window = wl_container_of(l, be_window, xdg_destroyed); + backend_t *be = be_window->be; + + // remove focus if it had focus + if(be->focus == be_window){ + // point keyboard at nothing + wlr_seat_keyboard_clear_focus(be->seat); + // no more focus + be->focus = NULL; + } +} + +static void handle_xdg_mapped(struct wl_listener *l, void *data){ + be_window_t *be_window = wl_container_of(l, be_window, xdg_mapped); + + be_window->mapped = true; + + logmsg("xdg mapped\n"); + + // set XDG to be fully tiled + wlr_xdg_toplevel_set_tiled(be_window->xdg_surface, 15); + + // call hook into venowm + handle_window_new(be_window, &be_window->venowm_data); +} + +static void handle_xdg_unmapped(struct wl_listener *l, void *data){ + be_window_t *be_window = wl_container_of(l, be_window, xdg_unmapped); + + be_window->mapped = false; + + logmsg("xdg unmapped\n"); + + /* TODO: can this happen any time, or only right before the application + closes? If it can happen frequently, it might not be good to unfocus + the window. This would be like some kind of guard against redraws. If + it happens rarely or only before close than this should affect things + like if the application is activated and where the keyboard focus is. + + By not adjusting focus or activation here, we are kinda assuming one, + but by calling handle_window_destroy we are kinda assuming the other. + */ + + // call hook into venowm + if(be_window->venowm_data){ + handle_window_destroy(be_window->venowm_data); + } +} + +// We have an xdg surface but it doesn't necessarily have a role yet. +static void handle_xdg_shell_new(struct wl_listener *l, void *data){ + struct wlr_xdg_surface *xdg_surface = data; + backend_t *be = wl_container_of(l, be, xdg_shell_new_listener); + + logmsg("new xdg_surface! %p\n", xdg_surface); + + // get the be_window from the wlr_surface under the xdg_surface + be_window_t *be_window = xdg_surface->surface->data; + + // if we got here but no be_window was allocated, close the application + if(!be_window){ + //// Wait, this isn't valid because the surface has no role yet. + // wlr_xdg_toplevel_send_close(xdg_surface); + // return; + // TODO: shit, we don't really have a way to handle this. + exit(101); + } + + // store the xdg_surface within the be_window + be_window->xdg_surface = xdg_surface; + + // hooks for the xdg_surface + be_window->xdg_destroyed.notify = handle_xdg_destroyed; + wl_signal_add(&xdg_surface->events.destroy, &be_window->xdg_destroyed); + + be_window->xdg_mapped.notify = handle_xdg_mapped; + wl_signal_add(&xdg_surface->events.map, &be_window->xdg_mapped); + + be_window->xdg_unmapped.notify = handle_xdg_unmapped; + wl_signal_add(&xdg_surface->events.unmap, &be_window->xdg_unmapped); + + // initial state + be_window->mapped = false; + + // don't call into venowm until the surface is mapped +} + +///// End Backend Window Functions + + +///// Decoration Functions + +void handle_decoration_new(struct wl_listener *l, void *data){ + backend_t *be = wl_container_of(l, be, decoration_new); + struct wlr_xdg_toplevel_decoration_v1 *dec = data; + + /* TODO: do we need to actually handle requests from the decoration? Or can + we just tell the decoration to use server-side decorations and + call it good? Let's give that a shot. */ + logmsg("new decoration!!!!!!!!!!!!!!!!!!!!!!!!\n"); + + // Fire and forget. Probably the return value means something. + uint32_t ret = wlr_xdg_toplevel_decoration_v1_set_mode(dec, + WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); + (void)ret; +} + +void handle_decoration_mgr_destroy(struct wl_listener *l, void *data){ + (void)data; + backend_t *be = wl_container_of(l, be, decoration_mgr_destroy); + /* TODO: should destroy() get called here or in backend free? Not both. + Actually, I would consider shutting down the whole compositor if + this died a valid plan. It shouldn't die. */ + (void)be; +} + +///// End Decoration Functions + + +void backend_free(backend_t *be){ + // free all the keymaps + { + keymap_t *keymap; + keymap_t *temp; + wl_list_for_each_safe(keymap, temp, &be->keymaps, link){ + keymap_free(keymap); + } + } + wlr_xcursor_manager_destroy(be->cursor_mgr); + wlr_cursor_destroy(be->cursor); + wlr_seat_destroy(be->seat); + wl_list_remove(&be->wlr_surface_created.link); + wl_list_remove(&be->compositor_destroyed_listener.link); + venowm_control_free(be->vc); + wlr_server_decoration_manager_destroy(be->server_dec_mgr); + wl_list_remove(&be->decoration_new.link); + wl_list_remove(&be->decoration_mgr_destroy.link); + wlr_xdg_decoration_manager_v1_destroy(be->decoration_mgr); + wl_list_remove(&be->xdg_shell_new_listener.link); + wlr_xdg_shell_destroy(be->xdg_shell); + // TODO: fix the order of things here + // this gets called during compositor_destroyed + // wlr_compositor_destroy(be->compositor); + wlr_output_layout_destroy(be->output_layout); + wl_list_remove(&be->new_output_listener.link); + wlr_backend_destroy(be->wlr_backend); + wl_display_destroy(be->display); + free(be); +} + +static void handle_compositor_destroyed(struct wl_listener *l, void *data){ + backend_t *be = wl_container_of(l, be, compositor_destroyed_listener); + backend_free(be); +} + +backend_t *backend_new(void){ + backend_t *be = malloc(sizeof(*be)); + if(!be) return NULL; + *be = (backend_t){0}; + + be->display = wl_display_create(); + if(!be->display) goto fail_be; + + be->loop = wl_display_get_event_loop(be->display); + if(!be->loop) goto fail_display; + + // get the wayland backend + be->wlr_backend = wlr_backend_autocreate(be->display, NULL); + if(!be->wlr_backend) goto fail_display; + be->new_input_device.notify = handle_new_input_device; + wl_signal_add(&be->wlr_backend->events.new_input, &be->new_input_device); + + // get ready for some outputs + wl_list_init(&be->be_screens); + be->new_output_listener.notify = handle_new_output; + wl_signal_add(&be->wlr_backend->events.new_output, + &be->new_output_listener); + + be->output_layout = wlr_output_layout_create(); + if(!be->output_layout) goto fail_wlr_backend; + + // add a compositor + be->compositor = wlr_compositor_create(be->display, + wlr_backend_get_renderer(be->wlr_backend)); + if(!be->compositor) goto fail_output_layout; + + // xdg_shell interface + be->xdg_shell = wlr_xdg_shell_create(be->display); + if(!be->xdg_shell) goto fail_compositor; + be->xdg_shell_new_listener.notify = handle_xdg_shell_new; + wl_signal_add(&be->xdg_shell->events.new_surface, + &be->xdg_shell_new_listener); + + // shared memory stuff + wl_display_init_shm(be->display); + + // xdg_decoration stuff + be->decoration_mgr = wlr_xdg_decoration_manager_v1_create(be->display); + if(!be->decoration_mgr) goto fail_xdg_shell; + be->decoration_new.notify = handle_decoration_new; + wl_signal_add(&be->decoration_mgr->events.new_toplevel_decoration, + &be->decoration_new); + be->decoration_mgr_destroy.notify = handle_decoration_mgr_destroy; + wl_signal_add(&be->decoration_mgr->events.destroy, + &be->decoration_mgr_destroy); + + // kde server decoration stuff + be->server_dec_mgr = wlr_server_decoration_manager_create(be->display); + if(!be->server_dec_mgr) goto fail_decoration_mgr; + wlr_server_decoration_manager_set_default_mode( + be->server_dec_mgr, WLR_SERVER_DECORATION_MANAGER_MODE_SERVER); + + // venowm_control interface + be->vc = venowm_control_new(be, be->display); + if(!be->vc) goto fail_server_dec_mgr; + + // become a proper wayland server + be->socket = wl_display_add_socket_auto(be->display); + if(!be->socket) goto fail_venowm_control; + + // add some listeners + be->wlr_surface_created.notify = handle_new_surface; + wl_signal_add(&be->compositor->events.new_surface, + &be->wlr_surface_created); + be->compositor_destroyed_listener.notify = handle_compositor_destroyed; + wl_signal_add(&be->compositor->events.destroy, + &be->compositor_destroyed_listener); + + // add a seat + be->seat = wlr_seat_create(be->display, "seat-name"); + if(!be->seat) goto fail_listeners; + + // prepare input lists + wl_list_init(&be->pointers); + wl_list_init(&be->keyboards); + // no keyboards or pointers yet + be->seat_caps = 0; + + // add a cursor + be->cursor = wlr_cursor_create(); + if(!be->cursor) goto fail_seat; + wlr_cursor_attach_output_layout(be->cursor, be->output_layout); + + // add a cursor manger + be->cursor_mgr = wlr_xcursor_manager_create("default", 24); + if(!be->cursor_mgr) goto fail_cursor; + + // load the default scale here + wlr_xcursor_manager_load(be->cursor_mgr, 1.0); + wlr_xcursor_manager_set_cursor_image( + be->cursor_mgr, "left_ptr", be->cursor); + + // prepare keymaps + wl_list_init(&be->keymaps); + be->keymap_top = keymap_new(be); + if(!be->keymap_top) goto fail_cursor_mgr; + + return be; + +// fail_keymaps: +// { +// keymap_t *keymap; +// keymap_t *temp; +// wl_list_for_each_safe(keymap, temp, &be->keymaps, link){ +// keymap_free(keymap); +// } +// } +fail_cursor_mgr: + wlr_xcursor_manager_destroy(be->cursor_mgr); +fail_cursor: + wlr_cursor_destroy(be->cursor); +fail_seat: + wlr_seat_destroy(be->seat); +fail_listeners: + wl_list_remove(&be->wlr_surface_created.link); + wl_list_remove(&be->compositor_destroyed_listener.link); +fail_venowm_control: + venowm_control_free(be->vc); +fail_server_dec_mgr: + wlr_server_decoration_manager_destroy(be->server_dec_mgr); +fail_decoration_mgr: + wl_list_remove(&be->decoration_new.link); + wl_list_remove(&be->decoration_mgr_destroy.link); + wlr_xdg_decoration_manager_v1_destroy(be->decoration_mgr); +fail_xdg_shell: + wl_list_remove(&be->xdg_shell_new_listener.link); + wlr_xdg_shell_destroy(be->xdg_shell); +fail_compositor: + wlr_compositor_destroy(be->compositor); +fail_output_layout: + wlr_output_layout_destroy(be->output_layout); +fail_wlr_backend: + wl_list_remove(&be->new_output_listener.link); + wlr_backend_destroy(be->wlr_backend); +fail_display: + wl_display_destroy(be->display); +fail_be: + free(be); + return NULL; +} + +static bool capture_q(backend_t *be, void *data){ + printf("q captured!\n"); + return true; +} + +int backend_run(backend_t *be){ + // start the backend + int ret = wlr_backend_start(be->wlr_backend); + if(!ret) return -1; + + setenv("WAYLAND_DISPLAY", be->socket, true); + + // exec("weston-info > wifo"); + exec("weston-terminal"); + + if(be_handle_key(be, 0, XKB_KEY_q, capture_q, NULL)){ + logmsg("failed to handle q\n"); + } + + wl_display_run(be->display); + // TODO: check error + return 0; +} + +void backend_stop(backend_t *be){ + wl_display_terminate(be->display); +} + +int be_handle_key(backend_t *be, uint32_t mods, uint32_t key, + bool (*func)(backend_t*, void*), void *data){ + // get the modded_key for the hashtable + uint32_t modded_keysym = (uint32_t)key; + if(mods & MOD_CTRL) modded_keysym |= BE_MOD_CTRL; + if(mods & MOD_SHIFT) modded_keysym |= BE_MOD_SHIFT; + if(mods & MOD_ALT) modded_keysym |= BE_MOD_ALT; + if(mods & MOD_SUPER) modded_keysym |= BE_MOD_SUPER; + + int ret; + ret = keymap_add_keybinding(be->keymap_top, modded_keysym, func, data); + if(ret < 0){ + return -1; + } + + return 0; +} + +void be_screen_get_geometry(be_screen_t *be_screen, int32_t *x, int32_t *y, + uint32_t *w, uint32_t *h){ + *x = 0; + *y = 0; + *w = (uint32_t)be_screen->output->width; + *h = (uint32_t)be_screen->output->height; +} + +void be_unfocus_all(backend_t *be){ + if(be->focus != NULL){ + // deactivate surface + wlr_xdg_toplevel_set_activated(be->focus->xdg_surface, false); + // point keyboard at nothing + wlr_seat_keyboard_clear_focus(be->seat); + // no more focus + be->focus = NULL; + } +} + +void be_window_focus(be_window_t *be_window){ + backend_t *be = be_window->be; + if(be->focus != NULL){ + // deactivate old surface + wlr_xdg_toplevel_set_activated(be->focus->xdg_surface, false); + } + + // activate new focus + wlr_xdg_toplevel_set_activated(be_window->xdg_surface, true); + + // point keyboard at new surface + struct wlr_keyboard *kbd = wlr_seat_get_keyboard(be->seat); + if(kbd){ + wlr_seat_keyboard_notify_enter(be->seat, be_window->wlr_surface, + kbd->keycodes, kbd->num_keycodes, &kbd->modifiers); + } + + be->focus = be_window; + logmsg("new focus window's role: %d\n", be_window->xdg_surface->role); +} + +void be_window_hide(be_window_t *be_window){ + backend_t *be = be_window->be; + if(!be_window->show) return; + be_window->show = false; + wl_list_remove(&be_window->link); + // if the window was focused, unfocus it + if(be->focus == be_window){ + be_unfocus_all(be); + } +} + +void be_window_show(be_window_t *be_window, be_screen_t *be_screen){ + if(be_window->show) return; + be_window->show = true; + // add this window to that screen + wl_list_insert(be_screen->windows.prev, &be_window->link); +} + +void be_window_close(be_window_t *be_window){ + wlr_xdg_toplevel_send_close(be_window->xdg_surface); + // TODO: handle popups as well +} + +void be_window_geometry(be_window_t *be_window, int32_t x, int32_t y, + uint32_t w, uint32_t h){ + uint32_t serial = wlr_xdg_toplevel_set_size(be_window->xdg_surface, w, h); + be_window->x = x; be_window->y = y; + logmsg("set_size serial is %u\n", serial); +} + +// request an explicit repaint +void be_repaint(backend_t *be){ +} diff --git a/bindings.c b/bindings.c index ac7344e..c2a69d4 100644 --- a/bindings.c +++ b/bindings.c @@ -1,5 +1,7 @@ #include #include +#include +#include #include "bindings.h" #include "logmsg.h" @@ -26,16 +28,13 @@ static void exec(const char *shcmd){ } #define DEFINE_KEY_HANDLER(func_name) \ - void func_name(struct weston_keyboard *keyboard, \ - const struct timespec *timespec, \ - uint32_t value, \ - void *data){ \ - (void)keyboard; (void)timespec; (void)value; \ - backend_t *be = data; \ - (void)be; + bool func_name(backend_t *be, void *data){ \ + bool retval = true; \ + (void)data; #define FINISH_KEY_HANDLER \ be_repaint(be); \ + return retval; \ } DEFINE_KEY_HANDLER(quit) @@ -107,36 +106,43 @@ DEFINE_KEY_HANDLER(prev_win) workspace_prev_hidden_win_at(g_workspace, g_workspace->focus); FINISH_KEY_HANDLER +DEFINE_KEY_HANDLER(close_window) + if(g_workspace->focus->win_info){ + be_window_close(g_workspace->focus->win_info->window->be_window); + } +FINISH_KEY_HANDLER + #define ADD_KEY(xkey, func) \ if(be_handle_key(be, MOD_CTRL, \ - KEY_ ## xkey, \ + XKB_KEY_ ## xkey, \ &func, be)){ \ goto fail; \ } #define ADD_KEY_SHIFT(xkey, func) \ if(be_handle_key(be, MOD_CTRL | MOD_SHIFT, \ - KEY_ ## xkey, \ + XKB_KEY_ ## xkey, \ &func, be)){ \ goto fail; \ } int add_bindings(backend_t *be){ - ADD_KEY(Q, quit); - ADD_KEY(ENTER, exec_weston_terminal); - ADD_KEY(BACKSLASH, dohsplit); - ADD_KEY(MINUS, dovsplit); - ADD_KEY(H, goleft); - ADD_KEY(J, godown); - ADD_KEY(K, goup); - ADD_KEY(L, goright); - ADD_KEY(Y, remove_frame); - ADD_KEY_SHIFT(H, swapleft); - ADD_KEY_SHIFT(J, swapdown); - ADD_KEY_SHIFT(K, swapup); - ADD_KEY_SHIFT(L, swapright); - ADD_KEY(SPACE, next_win); - ADD_KEY_SHIFT(SPACE, prev_win); + ADD_KEY(q, quit); + ADD_KEY(Return, exec_weston_terminal); + ADD_KEY(backslash, dohsplit); + ADD_KEY(minus, dovsplit); + ADD_KEY(h, goleft); + ADD_KEY(j, godown); + ADD_KEY(k, goup); + ADD_KEY(l, goright); + ADD_KEY(y, remove_frame); + ADD_KEY(i, close_window); + ADD_KEY_SHIFT(h, swapleft); + ADD_KEY_SHIFT(j, swapdown); + ADD_KEY_SHIFT(k, swapup); + ADD_KEY_SHIFT(l, swapright); + ADD_KEY(space, next_win); + ADD_KEY_SHIFT(space, prev_win); return 0; fail: diff --git a/makefile b/makefile index 22b0ebf..5b34dc4 100644 --- a/makefile +++ b/makefile @@ -1,26 +1,70 @@ CC=gcc LD=ld -# Hm... the libweston package is versioned explicitly but weston is not. This -# way of doing things is not safe. -PKGS=weston libweston-6 libweston-desktop-6 wayland-server +PKGS=wlroots wayland-client wayland-server xkbcommon +CFLAGS+=-DWLR_USE_UNSTABLE CFLAGS+=-g CFLAGS+=-Wall -Wextra -std=c11 -CFLAGS+=-fPIC +CFLAGS+=-Iprotocol CFLAGS+=`pkg-config --cflags $(PKGS)` CFLAGS+=-fdiagnostics-color=always +CFLAGS+=-Wno-unused-parameter + LDFLAGS+=`pkg-config --libs $(PKGS)` LDFLAGS+=-lm -LDFLAGS+=-shared -all: clean venowm_shell_plugin.so test_split +XDG_SHELL_XML=/usr/share/wayland-protocols/stable/xdg-shell/xdg-shell.xml + +all: venowm test_split test_split: split.o logmsg.o -venowm_shell_plugin.so: venowm_shell_plugin.o split.o screen.o workspace.o window.o logmsg.o bindings.o - $(CC) $(LDFLAGS) -o $@ $^ +backend_wlroots.o: protocol/xdg-shell-protocol.h \ + protocol/xdg-shell-protocol.c + +venowm_control.o: protocol/venowm-shell-protocol.h \ + protocol/venowm-shell-protocol.c + +venowm:split.o \ + screen.o \ + workspace.o \ + window.o \ + logmsg.o \ + bindings.o \ + venowm_control.o \ + backend_wlroots.o + +protocol/xdg-shell-protocol.h: $(XDG_SHELL_XML) + mkdir -p protocol + wayland-scanner server-header $< $@ + +protocol/xdg-shell-client-protocol.h: $(XDG_SHELL_XML) + wayland-scanner client-header $< $@ + +protocol/xdg-shell-protocol.c: $(XDG_SHELL_XML) + mkdir -p protocol + wayland-scanner private-code $< $@ + +protocol/venowm-shell-protocol.h: venowm-shell.xml + mkdir -p protocol + wayland-scanner server-header $< $@ + +protocol/venowm-shell-client-protocol.h: venowm-shell.xml + wayland-scanner client-header $< $@ + +protocol/venowm-shell-protocol.c: venowm-shell.xml + mkdir -p protocol + wayland-scanner private-code $< $@ + +.PHONY: protocols +protocols: protocol/xdg-shell-protocol.h \ + protocol/xdg-shell-client-protocol.h \ + protocol/xdg-shell-protocol.c \ + protocol/venowm-shell-protocol.h \ + protocol/venowm-shell-client-protocol.h \ + protocol/venowm-shell-protocol.c \ clean: - rm -f *.o venowm_shell_plugin.so test_split logmsg + rm -f *.o venowm test_split logmsg -r protocol diff --git a/venowm-shell.xml b/venowm-shell.xml new file mode 100644 index 0000000..0e11bd0 --- /dev/null +++ b/venowm-shell.xml @@ -0,0 +1,48 @@ + + + This is free and unencumbered software released into the public domain. + + Anyone is free to copy, modify, publish, use, compile, sell, or + distribute this software, either in source code form or as a compiled + binary, for any purpose, commercial or non-commercial, and by any + means. + + In jurisdictions that recognize copyright laws, the author or authors + of this software dedicate any and all copyright interest in the + software to the public domain. We make this dedication for the benefit + of the public at large and to the detriment of our heirs and + successors. We intend this dedication to be an overt act of + relinquishment in perpetuity of all present and future rights to this + software under copyright law. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + + For more information, please refer to http://unlicense.org/ + + + + + The venowm server provides this interface to allow scripted control of + the desktop interface. + + + + + + + + + + + + + + + + diff --git a/venowm.c b/venowm.c index 51fda1f..8181e10 100644 --- a/venowm.c +++ b/venowm.c @@ -14,6 +14,7 @@ #include "screen.h" #include "window.h" #include "workspace.h" +#include "bindings.h" // backend_t, needed for keybindings static backend_t *be; @@ -29,92 +30,6 @@ workspace_t **g_workspaces; size_t g_workspaces_size; size_t g_nworkspaces; -static void exec(const char *shcmd){ - logmsg("called exec\n"); - pid_t pid = fork(); - if(pid < 0){ - perror("fork"); - return; - } - if(pid == 0){ - // child - execl("/bin/sh", "/bin/sh", "-c", shcmd, NULL); - perror("execl"); - exit(127); - } - // parent continues with whatever it was doing - return; -} - -DEFINE_KEY_HANDLER(quit) - logmsg("called quit\n"); - backend_stop(be); -FINISH_KEY_HANDLER - -DEFINE_KEY_HANDLER(exec_vimb) - exec("env GDK_BACKEND=wayland vimb"); -FINISH_KEY_HANDLER - -DEFINE_KEY_HANDLER(dohsplit) - workspace_hsplit(g_workspace, g_workspace->focus, 0.5); -FINISH_KEY_HANDLER - -DEFINE_KEY_HANDLER(dovsplit) - workspace_vsplit(g_workspace, g_workspace->focus, 0.5); -FINISH_KEY_HANDLER - -DEFINE_KEY_HANDLER(goleft) - split_t *new = split_move_left(g_workspace->focus); - workspace_focus_frame(g_workspace, new); -FINISH_KEY_HANDLER - -DEFINE_KEY_HANDLER(goright) - split_t *new = split_move_right(g_workspace->focus); - workspace_focus_frame(g_workspace, new); -FINISH_KEY_HANDLER - -DEFINE_KEY_HANDLER(goup) - split_t *new = split_move_up(g_workspace->focus); - workspace_focus_frame(g_workspace, new); -FINISH_KEY_HANDLER - -DEFINE_KEY_HANDLER(godown) - split_t *new = split_move_down(g_workspace->focus); - workspace_focus_frame(g_workspace, new); -FINISH_KEY_HANDLER - -DEFINE_KEY_HANDLER(remove_frame) - workspace_remove_frame(g_workspace, g_workspace->focus); -FINISH_KEY_HANDLER - -DEFINE_KEY_HANDLER(swapleft) - split_t *new = split_move_left(g_workspace->focus); - workspace_swap_windows_from_frames(g_workspace->focus, new); -FINISH_KEY_HANDLER - -DEFINE_KEY_HANDLER(swapright) - split_t *new = split_move_right(g_workspace->focus); - workspace_swap_windows_from_frames(g_workspace->focus, new); -FINISH_KEY_HANDLER - -DEFINE_KEY_HANDLER(swapup) - split_t *new = split_move_up(g_workspace->focus); - workspace_swap_windows_from_frames(g_workspace->focus, new); -FINISH_KEY_HANDLER - -DEFINE_KEY_HANDLER(swapdown) - split_t *new = split_move_down(g_workspace->focus); - workspace_swap_windows_from_frames(g_workspace->focus, new); -FINISH_KEY_HANDLER - -DEFINE_KEY_HANDLER(next_win) - workspace_next_hidden_win_at(g_workspace, g_workspace->focus); -FINISH_KEY_HANDLER - -DEFINE_KEY_HANDLER(prev_win) - workspace_prev_hidden_win_at(g_workspace, g_workspace->focus); -FINISH_KEY_HANDLER - void sigchld_handler(int signum){ logmsg("handled sigchld\n"); (void)signum; @@ -136,17 +51,24 @@ int main(){ int retval = 0; int err; + // set the SIGCHLD handler signal(SIGCHLD, sigchld_handler); + be = backend_new(); + if(!be){; + return 99; + } + INIT_PTR(g_workspaces, g_workspaces_size, g_nworkspaces, 8, err); if(err){ - return 99; + retval = 99; + goto cu_backend; } // allocate some workspaces for(size_t i = 0; i <= 5; i ++){ - workspace_t *new = workspace_new(); + workspace_t *new = workspace_new(be); if(!new){ retval = 99; goto cu_workspaces; @@ -169,49 +91,13 @@ int main(){ goto cu_workspaces; } - be = backend_new(); - if(!be){ - goto cu_screens; - } - -#define ADD_KEY(xkey, func) \ - if(be_handle_key(be, MOD_CTRL, \ - KEY_ ## xkey, \ - &func, be)){ \ - retval = 6; \ - goto cu_backend; \ - } -#define ADD_KEY_SHIFT(xkey, func) \ - if(be_handle_key(be, MOD_CTRL | MOD_SHIFT, \ - KEY_ ## xkey, \ - &func, be)){ \ - retval = 6; \ - goto cu_backend; \ - } - ADD_KEY(Q, quit); - ADD_KEY(ENTER, exec_vimb); - ADD_KEY(BACKSLASH, dohsplit); - ADD_KEY(MINUS, dovsplit); - ADD_KEY(H, goleft); - ADD_KEY(J, godown); - ADD_KEY(K, goup); - ADD_KEY(L, goright); - ADD_KEY(Y, remove_frame); - ADD_KEY_SHIFT(H, swapleft); - ADD_KEY_SHIFT(J, swapdown); - ADD_KEY_SHIFT(K, swapup); - ADD_KEY_SHIFT(L, swapright); - ADD_KEY(SPACE, next_win); - ADD_KEY_SHIFT(SPACE, prev_win); -#undef ADD_KEY + if(add_bindings(be)) goto cu_workspaces; backend_run(be); logmsg("post run\n"); -cu_backend: - backend_free(be); -cu_screens: +//cu_screens: // screens are freed by the pre-destroy-screen handler FREE_PTR(g_screens, g_screens_size, g_nscreens); cu_workspaces: @@ -220,6 +106,8 @@ int main(){ workspace_free(g_workspaces[i]); } FREE_PTR(g_workspaces, g_workspaces_size, g_nworkspaces); +cu_backend: + backend_free(be); logmsg("exiting from main: %d\n", retval); return retval; } diff --git a/venowm_control.c b/venowm_control.c new file mode 100644 index 0000000..6d0ad07 --- /dev/null +++ b/venowm_control.c @@ -0,0 +1,107 @@ +#include "venowm_control.h" +#include "logmsg.h" +#include "venowm.h" +#include "workspace.h" +#include "split.h" + +#include "protocol/venowm-shell-protocol.h" + +static void venowm_control_focus_up(struct wl_client *client, + struct wl_resource *resource){ + (void)client; + + venowm_control_t *vc = wl_resource_get_user_data(resource); + + split_t *new = split_move_up(g_workspace->focus); + workspace_focus_frame(g_workspace, new); + be_repaint(vc->be); +} + +static void venowm_control_focus_down(struct wl_client *client, + struct wl_resource *resource){ + (void)client; + + venowm_control_t *vc = wl_resource_get_user_data(resource); + + split_t *new = split_move_down(g_workspace->focus); + workspace_focus_frame(g_workspace, new); + be_repaint(vc->be); +} + +static void venowm_control_focus_left(struct wl_client *client, + struct wl_resource *resource){ + (void)client; + + venowm_control_t *vc = wl_resource_get_user_data(resource); + + split_t *new = split_move_left(g_workspace->focus); + workspace_focus_frame(g_workspace, new); + be_repaint(vc->be); +} + +static void venowm_control_focus_right(struct wl_client *client, + struct wl_resource *resource){ + (void)client; + + venowm_control_t *vc = wl_resource_get_user_data(resource); + + split_t *new = split_move_right(g_workspace->focus); + workspace_focus_frame(g_workspace, new); + be_repaint(vc->be); +} + +static const struct venowm_control_interface venowm_control_impl = { + venowm_control_focus_up, + venowm_control_focus_down, + venowm_control_focus_left, + venowm_control_focus_right, +}; + +static void unbind_venowm_control(struct wl_resource *resource){ + venowm_control_t *vc = wl_resource_get_user_data(resource); + (void)vc; + + // TODO: figure out what to do + logmsg("unbinding venowm control, not sure what to do"); +} + +static void bind_venowm_control(struct wl_client *client, void *data, + uint32_t version, uint32_t id){ + venowm_control_t *vc = data; + struct wl_resource *resource; + + resource = wl_resource_create(client, &venowm_control_interface, 1, id); + if(!resource){ + wl_client_post_no_memory(client); + return; + } + + wl_resource_set_implementation(resource, &venowm_control_impl, vc, + unbind_venowm_control); +} + + +void venowm_control_free(venowm_control_t *vc){ + wl_global_destroy(vc->global); + free(vc); +} + +venowm_control_t *venowm_control_new(backend_t *be, + struct wl_display *display){ + venowm_control_t *vc = malloc(sizeof(*vc)); + if(!vc) return NULL; + *vc = (venowm_control_t){ + .be=be, + }; + + vc->global = wl_global_create(display, &venowm_control_interface, 1, + vc, bind_venowm_control); + if(!vc->global) goto fail_malloc; + + return vc; + +fail_malloc: + free(vc); + return NULL; +} + diff --git a/venowm_control.h b/venowm_control.h new file mode 100644 index 0000000..c778baa --- /dev/null +++ b/venowm_control.h @@ -0,0 +1,13 @@ +#include + +#include "backend.h" + +typedef struct { + backend_t *be; + struct wl_global *global; +} venowm_control_t; + + +void venowm_control_free(venowm_control_t *vc); + +venowm_control_t *venowm_control_new(backend_t *be, struct wl_display *display); diff --git a/venowm_shell_plugin.c b/venowm_shell_plugin.c index e971f43..5153226 100644 --- a/venowm_shell_plugin.c +++ b/venowm_shell_plugin.c @@ -206,14 +206,17 @@ void handle_seat_created(struct wl_listener *l, void *data){ ///// Desktop API functions -static void backend_handle_surface_commit(struct wl_listener *l, void *data){ - logmsg("handle_surface_commit()\n"); - (void)data; - be_window_t *be_window = wl_container_of(l, be_window, commit_listener); - backend_t *be = be_window->be; +static void handle_desktop_surface_committed( + struct weston_desktop_surface *surface, int32_t sx, int32_t sy, + void *user_data){ + logmsg("handle_desktop_surface_committed()\n"); + backend_t *be = user_data; + be_window_t *be_window = weston_desktop_surface_get_user_data(surface); // schedule a repaint - weston_compositor_schedule_repaint(be->compositor); + if(be_window->linked){ + weston_compositor_schedule_repaint(be->compositor); + } // TODO: don't schedule a repaint on every single commit // (why is this not working out-of-the-box??) @@ -305,6 +308,8 @@ static const struct weston_desktop_api desktop_api = { // minimal API requirements: .surface_added = handle_desktop_surface_added, .surface_removed = handle_desktop_surface_removed, + // additional things I want to implement + .committed = handle_desktop_surface_committed, }; ///// End Desktop API functions diff --git a/xkb.dump b/xkb.dump new file mode 100644 index 0000000..a6ec80b --- /dev/null +++ b/xkb.dump @@ -0,0 +1,1927 @@ +xkb_keymap { +xkb_keycodes "evdev+aliases(qwerty)" { + minimum = 8; + maximum = 255; + = 9; + = 10; + = 11; + = 12; + = 13; + = 14; + = 15; + = 16; + = 17; + = 18; + = 19; + = 20; + = 21; + = 22; + = 23; + = 24; + = 25; + = 26; + = 27; + = 28; + = 29; + = 30; + = 31; + = 32; + = 33; + = 34; + = 35; + = 36; + = 37; + = 38; + = 39; + = 40; + = 41; + = 42; + = 43; + = 44; + = 45; + = 46; + = 47; + = 48; + = 49; + = 50; + = 51; + = 52; + = 53; + = 54; + = 55; + = 56; + = 57; + = 58; + = 59; + = 60; + = 61; + = 62; + = 63; + = 64; + = 65; + = 66; + = 67; + = 68; + = 69; + = 70; + = 71; + = 72; + = 73; + = 74; + = 75; + = 76; + = 77; + = 78; + = 79; + = 80; + = 81; + = 82; + = 83; + = 84; + = 85; + = 86; + = 87; + = 88; + = 89; + = 90; + = 91; + = 92; + = 94; + = 95; + = 96; + = 97; + = 98; + = 99; + = 100; + = 101; + = 102; + = 103; + = 104; + = 105; + = 106; + = 107; + = 108; + = 109; + = 110; + = 111; + = 112; + = 113; + = 114; + = 115; + = 116; + = 117; + = 118; + = 119; + = 120; + = 121; + = 122; + = 123; + = 124; + = 125; + = 126; + = 127; + = 128; + = 129; + = 130; + = 131; + = 132; + = 133; + = 134; + = 135; + = 136; + = 137; + = 138; + = 139; + = 140; + = 141; + = 142; + = 143; + = 144; + = 145; + = 146; + = 147; + = 148; + = 149; + = 150; + = 151; + = 152; + = 153; + = 154; + = 155; + = 156; + = 157; + = 158; + = 159; + = 160; + = 161; + = 162; + = 163; + = 164; + = 165; + = 166; + = 167; + = 168; + = 169; + = 170; + = 171; + = 172; + = 173; + = 174; + = 175; + = 176; + = 177; + = 178; + = 179; + = 180; + = 181; + = 182; + = 183; + = 184; + = 185; + = 186; + = 187; + = 188; + = 189; + = 190; + = 191; + = 192; + = 193; + = 194; + = 195; + = 196; + = 197; + = 198; + = 199; + = 200; + = 201; + = 202; + = 203; + = 204; + = 205; + = 206; + = 207; + = 208; + = 209; + = 210; + = 211; + = 212; + = 213; + = 214; + = 215; + = 216; + = 217; + = 218; + = 219; + = 220; + = 221; + = 222; + = 223; + = 224; + = 225; + = 226; + = 227; + = 228; + = 229; + = 230; + = 231; + = 232; + = 233; + = 234; + = 235; + = 236; + = 237; + = 238; + = 239; + = 240; + = 241; + = 242; + = 243; + = 244; + = 245; + = 246; + = 247; + = 248; + = 249; + = 250; + = 251; + = 252; + = 253; + = 254; + = 255; + indicator 1 = "Caps Lock"; + indicator 2 = "Num Lock"; + indicator 3 = "Scroll Lock"; + indicator 4 = "Compose"; + indicator 5 = "Kana"; + indicator 6 = "Sleep"; + indicator 7 = "Suspend"; + indicator 8 = "Mute"; + indicator 9 = "Misc"; + indicator 10 = "Mail"; + indicator 11 = "Charging"; + virtual indicator 12 = "Shift Lock"; + virtual indicator 13 = "Group 2"; + virtual indicator 14 = "Mouse Keys"; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; + alias = ; +}; + +xkb_types "complete" { + + virtual_modifiers NumLock,Alt,LevelThree,LAlt,RAlt,RControl,LControl,ScrollLock,LevelFive,AltGr,Meta,Super,Hyper; + + type "ONE_LEVEL" { + modifiers= none; + level_name[Level1]= "Any"; + }; + type "TWO_LEVEL" { + modifiers= Shift; + map[Shift]= Level2; + level_name[Level1]= "Base"; + level_name[Level2]= "Shift"; + }; + type "ALPHABETIC" { + modifiers= Shift+Lock; + map[Shift]= Level2; + map[Lock]= Level2; + level_name[Level1]= "Base"; + level_name[Level2]= "Caps"; + }; + type "KEYPAD" { + modifiers= Shift+NumLock; + map[Shift]= Level2; + map[NumLock]= Level2; + level_name[Level1]= "Base"; + level_name[Level2]= "Number"; + }; + type "SHIFT+ALT" { + modifiers= Shift+Alt; + map[Shift+Alt]= Level2; + level_name[Level1]= "Base"; + level_name[Level2]= "Shift+Alt"; + }; + type "PC_SUPER_LEVEL2" { + modifiers= Mod4; + map[Mod4]= Level2; + level_name[Level1]= "Base"; + level_name[Level2]= "Super"; + }; + type "PC_CONTROL_LEVEL2" { + modifiers= Control; + map[Control]= Level2; + level_name[Level1]= "Base"; + level_name[Level2]= "Control"; + }; + type "PC_LCONTROL_LEVEL2" { + modifiers= LControl; + map[LControl]= Level2; + level_name[Level1]= "Base"; + level_name[Level2]= "LControl"; + }; + type "PC_RCONTROL_LEVEL2" { + modifiers= RControl; + map[RControl]= Level2; + level_name[Level1]= "Base"; + level_name[Level2]= "RControl"; + }; + type "PC_ALT_LEVEL2" { + modifiers= Alt; + map[Alt]= Level2; + level_name[Level1]= "Base"; + level_name[Level2]= "Alt"; + }; + type "PC_LALT_LEVEL2" { + modifiers= LAlt; + map[LAlt]= Level2; + level_name[Level1]= "Base"; + level_name[Level2]= "LAlt"; + }; + type "PC_RALT_LEVEL2" { + modifiers= RAlt; + map[RAlt]= Level2; + level_name[Level1]= "Base"; + level_name[Level2]= "RAlt"; + }; + type "CTRL+ALT" { + modifiers= Shift+Control+Alt+LevelThree; + map[Shift]= Level2; + preserve[Shift]= Shift; + map[LevelThree]= Level3; + map[Shift+LevelThree]= Level4; + preserve[Shift+LevelThree]= Shift; + map[Control+Alt]= Level5; + level_name[Level1]= "Base"; + level_name[Level2]= "Shift"; + level_name[Level3]= "Alt Base"; + level_name[Level4]= "Shift Alt"; + level_name[Level5]= "Ctrl+Alt"; + }; + type "LOCAL_EIGHT_LEVEL" { + modifiers= Shift+Lock+Control+LevelThree; + map[Shift+Lock]= Level1; + map[Shift]= Level2; + map[Lock]= Level2; + map[LevelThree]= Level3; + map[Shift+Lock+LevelThree]= Level3; + map[Shift+LevelThree]= Level4; + map[Lock+LevelThree]= Level4; + map[Control]= Level5; + map[Shift+Lock+Control]= Level5; + map[Shift+Control]= Level6; + map[Lock+Control]= Level6; + map[Control+LevelThree]= Level7; + map[Shift+Lock+Control+LevelThree]= Level7; + map[Shift+Control+LevelThree]= Level8; + map[Lock+Control+LevelThree]= Level8; + level_name[Level1]= "Base"; + level_name[Level2]= "Shift"; + level_name[Level3]= "Level3"; + level_name[Level4]= "Shift Level3"; + level_name[Level5]= "Ctrl"; + level_name[Level6]= "Shift Ctrl"; + level_name[Level7]= "Level3 Ctrl"; + level_name[Level8]= "Shift Level3 Ctrl"; + }; + type "THREE_LEVEL" { + modifiers= Shift+LevelThree; + map[Shift]= Level2; + map[LevelThree]= Level3; + map[Shift+LevelThree]= Level3; + level_name[Level1]= "Base"; + level_name[Level2]= "Shift"; + level_name[Level3]= "Level3"; + }; + type "EIGHT_LEVEL" { + modifiers= Shift+LevelThree+LevelFive; + map[Shift]= Level2; + map[LevelThree]= Level3; + map[Shift+LevelThree]= Level4; + map[LevelFive]= Level5; + map[Shift+LevelFive]= Level6; + map[LevelThree+LevelFive]= Level7; + map[Shift+LevelThree+LevelFive]= Level8; + level_name[Level1]= "Base"; + level_name[Level2]= "Shift"; + level_name[Level3]= "Alt Base"; + level_name[Level4]= "Shift Alt"; + level_name[Level5]= "X"; + level_name[Level6]= "X Shift"; + level_name[Level7]= "X Alt Base"; + level_name[Level8]= "X Shift Alt"; + }; + type "EIGHT_LEVEL_ALPHABETIC" { + modifiers= Shift+Lock+LevelThree+LevelFive; + map[Shift]= Level2; + map[Lock]= Level2; + map[LevelThree]= Level3; + map[Shift+LevelThree]= Level4; + map[Lock+LevelThree]= Level4; + map[Shift+Lock+LevelThree]= Level3; + map[LevelFive]= Level5; + map[Shift+LevelFive]= Level6; + map[Lock+LevelFive]= Level6; + map[LevelThree+LevelFive]= Level7; + map[Shift+LevelThree+LevelFive]= Level8; + map[Lock+LevelThree+LevelFive]= Level8; + map[Shift+Lock+LevelThree+LevelFive]= Level7; + level_name[Level1]= "Base"; + level_name[Level2]= "Shift"; + level_name[Level3]= "Alt Base"; + level_name[Level4]= "Shift Alt"; + level_name[Level5]= "X"; + level_name[Level6]= "X Shift"; + level_name[Level7]= "X Alt Base"; + level_name[Level8]= "X Shift Alt"; + }; + type "EIGHT_LEVEL_LEVEL_FIVE_LOCK" { + modifiers= Shift+Lock+NumLock+LevelThree+LevelFive; + map[Shift]= Level2; + map[LevelThree]= Level3; + map[Shift+LevelThree]= Level4; + map[LevelFive]= Level5; + map[Shift+LevelFive]= Level6; + preserve[Shift+LevelFive]= Shift; + map[LevelThree+LevelFive]= Level7; + map[Shift+LevelThree+LevelFive]= Level8; + map[NumLock]= Level5; + map[Shift+NumLock]= Level6; + preserve[Shift+NumLock]= Shift; + map[NumLock+LevelThree]= Level7; + map[Shift+NumLock+LevelThree]= Level8; + map[Shift+NumLock+LevelFive]= Level2; + map[NumLock+LevelThree+LevelFive]= Level3; + map[Shift+NumLock+LevelThree+LevelFive]= Level4; + map[Shift+Lock]= Level2; + map[Lock+LevelThree]= Level3; + map[Shift+Lock+LevelThree]= Level4; + map[Lock+LevelFive]= Level5; + map[Shift+Lock+LevelFive]= Level6; + preserve[Shift+Lock+LevelFive]= Shift; + map[Lock+LevelThree+LevelFive]= Level7; + map[Shift+Lock+LevelThree+LevelFive]= Level8; + map[Lock+NumLock]= Level5; + map[Shift+Lock+NumLock]= Level6; + preserve[Shift+Lock+NumLock]= Shift; + map[Lock+NumLock+LevelThree]= Level7; + map[Shift+Lock+NumLock+LevelThree]= Level8; + map[Shift+Lock+NumLock+LevelFive]= Level2; + map[Lock+NumLock+LevelThree+LevelFive]= Level3; + map[Shift+Lock+NumLock+LevelThree+LevelFive]= Level4; + level_name[Level1]= "Base"; + level_name[Level2]= "Shift"; + level_name[Level3]= "Alt Base"; + level_name[Level4]= "Shift Alt"; + level_name[Level5]= "X"; + level_name[Level6]= "X Shift"; + level_name[Level7]= "X Alt Base"; + level_name[Level8]= "X Shift Alt"; + }; + type "EIGHT_LEVEL_ALPHABETIC_LEVEL_FIVE_LOCK" { + modifiers= Shift+Lock+NumLock+LevelThree+LevelFive; + map[Shift]= Level2; + map[LevelThree]= Level3; + map[Shift+LevelThree]= Level4; + map[LevelFive]= Level5; + map[Shift+LevelFive]= Level6; + preserve[Shift+LevelFive]= Shift; + map[LevelThree+LevelFive]= Level7; + map[Shift+LevelThree+LevelFive]= Level8; + map[NumLock]= Level5; + map[Shift+NumLock]= Level6; + preserve[Shift+NumLock]= Shift; + map[NumLock+LevelThree]= Level7; + map[Shift+NumLock+LevelThree]= Level8; + map[Shift+NumLock+LevelFive]= Level2; + map[NumLock+LevelThree+LevelFive]= Level3; + map[Shift+NumLock+LevelThree+LevelFive]= Level4; + map[Lock]= Level2; + map[Lock+LevelThree]= Level3; + map[Shift+Lock+LevelThree]= Level4; + map[Lock+LevelFive]= Level5; + map[Shift+Lock+LevelFive]= Level6; + map[Lock+LevelThree+LevelFive]= Level7; + map[Shift+Lock+LevelThree+LevelFive]= Level8; + map[Lock+NumLock]= Level5; + map[Shift+Lock+NumLock]= Level6; + map[Lock+NumLock+LevelThree]= Level7; + map[Shift+Lock+NumLock+LevelThree]= Level8; + map[Lock+NumLock+LevelFive]= Level2; + map[Lock+NumLock+LevelThree+LevelFive]= Level4; + map[Shift+Lock+NumLock+LevelThree+LevelFive]= Level3; + level_name[Level1]= "Base"; + level_name[Level2]= "Shift"; + level_name[Level3]= "Alt Base"; + level_name[Level4]= "Shift Alt"; + level_name[Level5]= "X"; + level_name[Level6]= "X Shift"; + level_name[Level7]= "X Alt Base"; + level_name[Level8]= "X Shift Alt"; + }; + type "EIGHT_LEVEL_SEMIALPHABETIC" { + modifiers= Shift+Lock+LevelThree+LevelFive; + map[Shift]= Level2; + map[Lock]= Level2; + map[LevelThree]= Level3; + map[Shift+LevelThree]= Level4; + map[Lock+LevelThree]= Level3; + preserve[Lock+LevelThree]= Lock; + map[Shift+Lock+LevelThree]= Level4; + preserve[Shift+Lock+LevelThree]= Lock; + map[LevelFive]= Level5; + map[Shift+LevelFive]= Level6; + map[Lock+LevelFive]= Level6; + preserve[Lock+LevelFive]= Lock; + map[Shift+Lock+LevelFive]= Level6; + preserve[Shift+Lock+LevelFive]= Lock; + map[LevelThree+LevelFive]= Level7; + map[Shift+LevelThree+LevelFive]= Level8; + map[Lock+LevelThree+LevelFive]= Level7; + preserve[Lock+LevelThree+LevelFive]= Lock; + map[Shift+Lock+LevelThree+LevelFive]= Level8; + preserve[Shift+Lock+LevelThree+LevelFive]= Lock; + level_name[Level1]= "Base"; + level_name[Level2]= "Shift"; + level_name[Level3]= "Alt Base"; + level_name[Level4]= "Shift Alt"; + level_name[Level5]= "X"; + level_name[Level6]= "X Shift"; + level_name[Level7]= "X Alt Base"; + level_name[Level8]= "X Shift Alt"; + }; + type "FOUR_LEVEL" { + modifiers= Shift+LevelThree; + map[Shift]= Level2; + map[LevelThree]= Level3; + map[Shift+LevelThree]= Level4; + level_name[Level1]= "Base"; + level_name[Level2]= "Shift"; + level_name[Level3]= "Alt Base"; + level_name[Level4]= "Shift Alt"; + }; + type "FOUR_LEVEL_ALPHABETIC" { + modifiers= Shift+Lock+LevelThree; + map[Shift]= Level2; + map[Lock]= Level2; + map[LevelThree]= Level3; + map[Shift+LevelThree]= Level4; + map[Lock+LevelThree]= Level4; + map[Shift+Lock+LevelThree]= Level3; + level_name[Level1]= "Base"; + level_name[Level2]= "Shift"; + level_name[Level3]= "Alt Base"; + level_name[Level4]= "Shift Alt"; + }; + type "FOUR_LEVEL_SEMIALPHABETIC" { + modifiers= Shift+Lock+LevelThree; + map[Shift]= Level2; + map[Lock]= Level2; + map[LevelThree]= Level3; + map[Shift+LevelThree]= Level4; + map[Lock+LevelThree]= Level3; + preserve[Lock+LevelThree]= Lock; + map[Shift+Lock+LevelThree]= Level4; + preserve[Shift+Lock+LevelThree]= Lock; + level_name[Level1]= "Base"; + level_name[Level2]= "Shift"; + level_name[Level3]= "Alt Base"; + level_name[Level4]= "Shift Alt"; + }; + type "FOUR_LEVEL_MIXED_KEYPAD" { + modifiers= Shift+NumLock+LevelThree; + map[Shift+NumLock]= Level1; + map[NumLock]= Level2; + map[Shift]= Level2; + map[LevelThree]= Level3; + map[NumLock+LevelThree]= Level3; + map[Shift+LevelThree]= Level4; + map[Shift+NumLock+LevelThree]= Level4; + level_name[Level1]= "Base"; + level_name[Level2]= "Number"; + level_name[Level3]= "Alt Base"; + level_name[Level4]= "Shift Alt"; + }; + type "FOUR_LEVEL_X" { + modifiers= Shift+Control+Alt+LevelThree; + map[LevelThree]= Level2; + map[Shift+LevelThree]= Level3; + map[Control+Alt]= Level4; + level_name[Level1]= "Base"; + level_name[Level2]= "Alt Base"; + level_name[Level3]= "Shift Alt"; + level_name[Level4]= "Ctrl+Alt"; + }; + type "SEPARATE_CAPS_AND_SHIFT_ALPHABETIC" { + modifiers= Shift+Lock+LevelThree; + map[Shift]= Level2; + map[Lock]= Level4; + preserve[Lock]= Lock; + map[LevelThree]= Level3; + map[Shift+LevelThree]= Level4; + map[Lock+LevelThree]= Level3; + preserve[Lock+LevelThree]= Lock; + map[Shift+Lock+LevelThree]= Level3; + level_name[Level1]= "Base"; + level_name[Level2]= "Shift"; + level_name[Level3]= "AltGr Base"; + level_name[Level4]= "Shift AltGr"; + }; + type "FOUR_LEVEL_PLUS_LOCK" { + modifiers= Shift+Lock+LevelThree; + map[Shift]= Level2; + map[LevelThree]= Level3; + map[Shift+LevelThree]= Level4; + map[Lock]= Level5; + map[Shift+Lock]= Level2; + map[Lock+LevelThree]= Level3; + map[Shift+Lock+LevelThree]= Level4; + level_name[Level1]= "Base"; + level_name[Level2]= "Shift"; + level_name[Level3]= "Alt Base"; + level_name[Level4]= "Shift Alt"; + level_name[Level5]= "Lock"; + }; + type "FOUR_LEVEL_KEYPAD" { + modifiers= Shift+NumLock+LevelThree; + map[Shift]= Level2; + map[NumLock]= Level2; + map[LevelThree]= Level3; + map[Shift+LevelThree]= Level4; + map[NumLock+LevelThree]= Level4; + map[Shift+NumLock+LevelThree]= Level3; + level_name[Level1]= "Base"; + level_name[Level2]= "Number"; + level_name[Level3]= "Alt Base"; + level_name[Level4]= "Alt Number"; + }; +}; + +xkb_compatibility "complete" { + + virtual_modifiers NumLock,Alt,LevelThree,LAlt,RAlt,RControl,LControl,ScrollLock,LevelFive,AltGr,Meta,Super,Hyper; + + interpret.useModMapMods= AnyLevel; + interpret.repeat= False; + interpret.locking= False; + interpret ISO_Level2_Latch+Exactly(Shift) { + useModMapMods=level1; + action= LatchMods(modifiers=Shift,clearLocks,latchToLock); + }; + interpret Shift_Lock+AnyOf(Shift+Lock) { + action= LockMods(modifiers=Shift); + }; + interpret Num_Lock+AnyOf(all) { + virtualModifier= NumLock; + action= LockMods(modifiers=NumLock); + }; + interpret ISO_Level3_Shift+AnyOf(all) { + virtualModifier= LevelThree; + useModMapMods=level1; + action= SetMods(modifiers=LevelThree,clearLocks); + }; + interpret ISO_Level3_Latch+AnyOf(all) { + virtualModifier= LevelThree; + useModMapMods=level1; + action= LatchMods(modifiers=LevelThree,clearLocks,latchToLock); + }; + interpret ISO_Level3_Lock+AnyOf(all) { + virtualModifier= LevelThree; + useModMapMods=level1; + action= LockMods(modifiers=LevelThree); + }; + interpret Alt_L+AnyOf(all) { + virtualModifier= Alt; + action= SetMods(modifiers=modMapMods,clearLocks); + }; + interpret Alt_R+AnyOf(all) { + virtualModifier= Alt; + action= SetMods(modifiers=modMapMods,clearLocks); + }; + interpret Meta_L+AnyOf(all) { + virtualModifier= Meta; + action= SetMods(modifiers=modMapMods,clearLocks); + }; + interpret Meta_R+AnyOf(all) { + virtualModifier= Meta; + action= SetMods(modifiers=modMapMods,clearLocks); + }; + interpret Super_L+AnyOf(all) { + virtualModifier= Super; + action= SetMods(modifiers=modMapMods,clearLocks); + }; + interpret Super_R+AnyOf(all) { + virtualModifier= Super; + action= SetMods(modifiers=modMapMods,clearLocks); + }; + interpret Hyper_L+AnyOf(all) { + virtualModifier= Hyper; + action= SetMods(modifiers=modMapMods,clearLocks); + }; + interpret Hyper_R+AnyOf(all) { + virtualModifier= Hyper; + action= SetMods(modifiers=modMapMods,clearLocks); + }; + interpret Scroll_Lock+AnyOf(all) { + virtualModifier= ScrollLock; + action= LockMods(modifiers=modMapMods); + }; + interpret ISO_Level5_Shift+AnyOf(all) { + virtualModifier= LevelFive; + useModMapMods=level1; + action= SetMods(modifiers=LevelFive,clearLocks); + }; + interpret ISO_Level5_Latch+AnyOf(all) { + virtualModifier= LevelFive; + useModMapMods=level1; + action= LatchMods(modifiers=LevelFive,clearLocks,latchToLock); + }; + interpret ISO_Level5_Lock+AnyOf(all) { + virtualModifier= LevelFive; + useModMapMods=level1; + action= LockMods(modifiers=LevelFive); + }; + interpret Mode_switch+AnyOfOrNone(all) { + virtualModifier= AltGr; + useModMapMods=level1; + action= SetGroup(group=+1); + }; + interpret ISO_Level3_Shift+AnyOfOrNone(all) { + action= SetMods(modifiers=LevelThree,clearLocks); + }; + interpret ISO_Level3_Latch+AnyOfOrNone(all) { + action= LatchMods(modifiers=LevelThree,clearLocks,latchToLock); + }; + interpret ISO_Level3_Lock+AnyOfOrNone(all) { + action= LockMods(modifiers=LevelThree); + }; + interpret ISO_Group_Latch+AnyOfOrNone(all) { + virtualModifier= AltGr; + useModMapMods=level1; + action= LatchGroup(group=2); + }; + interpret ISO_Next_Group+AnyOfOrNone(all) { + virtualModifier= AltGr; + useModMapMods=level1; + action= LockGroup(group=+1); + }; + interpret ISO_Prev_Group+AnyOfOrNone(all) { + virtualModifier= AltGr; + useModMapMods=level1; + action= LockGroup(group=-1); + }; + interpret ISO_First_Group+AnyOfOrNone(all) { + action= LockGroup(group=1); + }; + interpret ISO_Last_Group+AnyOfOrNone(all) { + action= LockGroup(group=2); + }; + interpret KP_1+AnyOfOrNone(all) { + repeat= True; + action= MovePtr(x=-1,y=+1); + }; + interpret KP_End+AnyOfOrNone(all) { + repeat= True; + action= MovePtr(x=-1,y=+1); + }; + interpret KP_2+AnyOfOrNone(all) { + repeat= True; + action= MovePtr(x=+0,y=+1); + }; + interpret KP_Down+AnyOfOrNone(all) { + repeat= True; + action= MovePtr(x=+0,y=+1); + }; + interpret KP_3+AnyOfOrNone(all) { + repeat= True; + action= MovePtr(x=+1,y=+1); + }; + interpret KP_Next+AnyOfOrNone(all) { + repeat= True; + action= MovePtr(x=+1,y=+1); + }; + interpret KP_4+AnyOfOrNone(all) { + repeat= True; + action= MovePtr(x=-1,y=+0); + }; + interpret KP_Left+AnyOfOrNone(all) { + repeat= True; + action= MovePtr(x=-1,y=+0); + }; + interpret KP_6+AnyOfOrNone(all) { + repeat= True; + action= MovePtr(x=+1,y=+0); + }; + interpret KP_Right+AnyOfOrNone(all) { + repeat= True; + action= MovePtr(x=+1,y=+0); + }; + interpret KP_7+AnyOfOrNone(all) { + repeat= True; + action= MovePtr(x=-1,y=-1); + }; + interpret KP_Home+AnyOfOrNone(all) { + repeat= True; + action= MovePtr(x=-1,y=-1); + }; + interpret KP_8+AnyOfOrNone(all) { + repeat= True; + action= MovePtr(x=+0,y=-1); + }; + interpret KP_Up+AnyOfOrNone(all) { + repeat= True; + action= MovePtr(x=+0,y=-1); + }; + interpret KP_9+AnyOfOrNone(all) { + repeat= True; + action= MovePtr(x=+1,y=-1); + }; + interpret KP_Prior+AnyOfOrNone(all) { + repeat= True; + action= MovePtr(x=+1,y=-1); + }; + interpret KP_5+AnyOfOrNone(all) { + repeat= True; + action= PtrBtn(button=default); + }; + interpret KP_Begin+AnyOfOrNone(all) { + repeat= True; + action= PtrBtn(button=default); + }; + interpret KP_F2+AnyOfOrNone(all) { + repeat= True; + action= SetPtrDflt(affect=button,button=1); + }; + interpret KP_Divide+AnyOfOrNone(all) { + repeat= True; + action= SetPtrDflt(affect=button,button=1); + }; + interpret KP_F3+AnyOfOrNone(all) { + repeat= True; + action= SetPtrDflt(affect=button,button=2); + }; + interpret KP_Multiply+AnyOfOrNone(all) { + repeat= True; + action= SetPtrDflt(affect=button,button=2); + }; + interpret KP_F4+AnyOfOrNone(all) { + repeat= True; + action= SetPtrDflt(affect=button,button=3); + }; + interpret KP_Subtract+AnyOfOrNone(all) { + repeat= True; + action= SetPtrDflt(affect=button,button=3); + }; + interpret KP_Separator+AnyOfOrNone(all) { + repeat= True; + action= PtrBtn(button=default,count=2); + }; + interpret KP_Add+AnyOfOrNone(all) { + repeat= True; + action= PtrBtn(button=default,count=2); + }; + interpret KP_0+AnyOfOrNone(all) { + repeat= True; + action= LockPtrBtn(button=default,affect=lock); + }; + interpret KP_Insert+AnyOfOrNone(all) { + repeat= True; + action= LockPtrBtn(button=default,affect=lock); + }; + interpret KP_Decimal+AnyOfOrNone(all) { + repeat= True; + action= LockPtrBtn(button=default,affect=unlock); + }; + interpret KP_Delete+AnyOfOrNone(all) { + repeat= True; + action= LockPtrBtn(button=default,affect=unlock); + }; + interpret F25+AnyOfOrNone(all) { + repeat= True; + action= SetPtrDflt(affect=button,button=1); + }; + interpret F26+AnyOfOrNone(all) { + repeat= True; + action= SetPtrDflt(affect=button,button=2); + }; + interpret F27+AnyOfOrNone(all) { + repeat= True; + action= MovePtr(x=-1,y=-1); + }; + interpret F29+AnyOfOrNone(all) { + repeat= True; + action= MovePtr(x=+1,y=-1); + }; + interpret F31+AnyOfOrNone(all) { + repeat= True; + action= PtrBtn(button=default); + }; + interpret F33+AnyOfOrNone(all) { + repeat= True; + action= MovePtr(x=-1,y=+1); + }; + interpret F35+AnyOfOrNone(all) { + repeat= True; + action= MovePtr(x=+1,y=+1); + }; + interpret Pointer_Button_Dflt+AnyOfOrNone(all) { + action= PtrBtn(button=default); + }; + interpret Pointer_Button1+AnyOfOrNone(all) { + action= PtrBtn(button=1); + }; + interpret Pointer_Button2+AnyOfOrNone(all) { + action= PtrBtn(button=2); + }; + interpret Pointer_Button3+AnyOfOrNone(all) { + action= PtrBtn(button=3); + }; + interpret Pointer_DblClick_Dflt+AnyOfOrNone(all) { + action= PtrBtn(button=default,count=2); + }; + interpret Pointer_DblClick1+AnyOfOrNone(all) { + action= PtrBtn(button=1,count=2); + }; + interpret Pointer_DblClick2+AnyOfOrNone(all) { + action= PtrBtn(button=2,count=2); + }; + interpret Pointer_DblClick3+AnyOfOrNone(all) { + action= PtrBtn(button=3,count=2); + }; + interpret Pointer_Drag_Dflt+AnyOfOrNone(all) { + action= LockPtrBtn(button=default,affect=both); + }; + interpret Pointer_Drag1+AnyOfOrNone(all) { + action= LockPtrBtn(button=1,affect=both); + }; + interpret Pointer_Drag2+AnyOfOrNone(all) { + action= LockPtrBtn(button=2,affect=both); + }; + interpret Pointer_Drag3+AnyOfOrNone(all) { + action= LockPtrBtn(button=3,affect=both); + }; + interpret Pointer_EnableKeys+AnyOfOrNone(all) { + action= LockControls(controls=MouseKeys); + }; + interpret Pointer_Accelerate+AnyOfOrNone(all) { + action= LockControls(controls=MouseKeysAccel); + }; + interpret Pointer_DfltBtnNext+AnyOfOrNone(all) { + action= SetPtrDflt(affect=button,button=+1); + }; + interpret Pointer_DfltBtnPrev+AnyOfOrNone(all) { + action= SetPtrDflt(affect=button,button=-1); + }; + interpret AccessX_Enable+AnyOfOrNone(all) { + action= LockControls(controls=AccessXKeys); + }; + interpret AccessX_Feedback_Enable+AnyOfOrNone(all) { + action= LockControls(controls=AccessXFeedback); + }; + interpret RepeatKeys_Enable+AnyOfOrNone(all) { + action= LockControls(controls=RepeatKeys); + }; + interpret SlowKeys_Enable+AnyOfOrNone(all) { + action= LockControls(controls=SlowKeys); + }; + interpret BounceKeys_Enable+AnyOfOrNone(all) { + action= LockControls(controls=BounceKeys); + }; + interpret StickyKeys_Enable+AnyOfOrNone(all) { + action= LockControls(controls=StickyKeys); + }; + interpret MouseKeys_Enable+AnyOfOrNone(all) { + action= LockControls(controls=MouseKeys); + }; + interpret MouseKeys_Accel_Enable+AnyOfOrNone(all) { + action= LockControls(controls=MouseKeysAccel); + }; + interpret Overlay1_Enable+AnyOfOrNone(all) { + action= LockControls(controls=Overlay1); + }; + interpret Overlay2_Enable+AnyOfOrNone(all) { + action= LockControls(controls=Overlay2); + }; + interpret AudibleBell_Enable+AnyOfOrNone(all) { + action= LockControls(controls=AudibleBell); + }; + interpret Terminate_Server+AnyOfOrNone(all) { + action= Terminate(); + }; + interpret Alt_L+AnyOfOrNone(all) { + action= SetMods(modifiers=Alt,clearLocks); + }; + interpret Alt_R+AnyOfOrNone(all) { + action= SetMods(modifiers=Alt,clearLocks); + }; + interpret Meta_L+AnyOfOrNone(all) { + action= SetMods(modifiers=Meta,clearLocks); + }; + interpret Meta_R+AnyOfOrNone(all) { + action= SetMods(modifiers=Meta,clearLocks); + }; + interpret Super_L+AnyOfOrNone(all) { + action= SetMods(modifiers=Super,clearLocks); + }; + interpret Super_R+AnyOfOrNone(all) { + action= SetMods(modifiers=Super,clearLocks); + }; + interpret Hyper_L+AnyOfOrNone(all) { + action= SetMods(modifiers=Hyper,clearLocks); + }; + interpret Hyper_R+AnyOfOrNone(all) { + action= SetMods(modifiers=Hyper,clearLocks); + }; + interpret Shift_L+AnyOfOrNone(all) { + action= SetMods(modifiers=Shift,clearLocks); + }; + interpret XF86Switch_VT_1+AnyOfOrNone(all) { + repeat= True; + action= SwitchScreen(screen=1,!same); + }; + interpret XF86Switch_VT_2+AnyOfOrNone(all) { + repeat= True; + action= SwitchScreen(screen=2,!same); + }; + interpret XF86Switch_VT_3+AnyOfOrNone(all) { + repeat= True; + action= SwitchScreen(screen=3,!same); + }; + interpret XF86Switch_VT_4+AnyOfOrNone(all) { + repeat= True; + action= SwitchScreen(screen=4,!same); + }; + interpret XF86Switch_VT_5+AnyOfOrNone(all) { + repeat= True; + action= SwitchScreen(screen=5,!same); + }; + interpret XF86Switch_VT_6+AnyOfOrNone(all) { + repeat= True; + action= SwitchScreen(screen=6,!same); + }; + interpret XF86Switch_VT_7+AnyOfOrNone(all) { + repeat= True; + action= SwitchScreen(screen=7,!same); + }; + interpret XF86Switch_VT_8+AnyOfOrNone(all) { + repeat= True; + action= SwitchScreen(screen=8,!same); + }; + interpret XF86Switch_VT_9+AnyOfOrNone(all) { + repeat= True; + action= SwitchScreen(screen=9,!same); + }; + interpret XF86Switch_VT_10+AnyOfOrNone(all) { + repeat= True; + action= SwitchScreen(screen=10,!same); + }; + interpret XF86Switch_VT_11+AnyOfOrNone(all) { + repeat= True; + action= SwitchScreen(screen=11,!same); + }; + interpret XF86Switch_VT_12+AnyOfOrNone(all) { + repeat= True; + action= SwitchScreen(screen=12,!same); + }; + interpret XF86LogGrabInfo+AnyOfOrNone(all) { + repeat= True; + action= Private(type=0x86,data[0]=0x50,data[1]=0x72,data[2]=0x47,data[3]=0x72,data[4]=0x62,data[5]=0x73,data[6]=0x00); + }; + interpret XF86LogWindowTree+AnyOfOrNone(all) { + repeat= True; + action= Private(type=0x86,data[0]=0x50,data[1]=0x72,data[2]=0x57,data[3]=0x69,data[4]=0x6e,data[5]=0x73,data[6]=0x00); + }; + interpret XF86Next_VMode+AnyOfOrNone(all) { + repeat= True; + action= Private(type=0x86,data[0]=0x2b,data[1]=0x56,data[2]=0x4d,data[3]=0x6f,data[4]=0x64,data[5]=0x65,data[6]=0x00); + }; + interpret XF86Prev_VMode+AnyOfOrNone(all) { + repeat= True; + action= Private(type=0x86,data[0]=0x2d,data[1]=0x56,data[2]=0x4d,data[3]=0x6f,data[4]=0x64,data[5]=0x65,data[6]=0x00); + }; + interpret ISO_Level5_Shift+AnyOfOrNone(all) { + action= SetMods(modifiers=LevelFive,clearLocks); + }; + interpret ISO_Level5_Latch+AnyOfOrNone(all) { + action= LatchMods(modifiers=LevelFive,clearLocks,latchToLock); + }; + interpret ISO_Level5_Lock+AnyOfOrNone(all) { + action= LockMods(modifiers=LevelFive); + }; + interpret Caps_Lock+AnyOfOrNone(all) { + action= LockMods(modifiers=Lock); + }; + interpret Any+Exactly(Lock) { + action= LockMods(modifiers=Lock); + }; + interpret Any+AnyOf(all) { + action= SetMods(modifiers=modMapMods,clearLocks); + }; + group 2 = AltGr; + group 3 = AltGr; + group 4 = AltGr; + indicator "Caps Lock" { + !allowExplicit; + whichModState= locked; + modifiers= Lock; + }; + indicator "Num Lock" { + !allowExplicit; + whichModState= locked; + modifiers= NumLock; + }; + indicator "Scroll Lock" { + whichModState= locked; + modifiers= ScrollLock; + }; + indicator "Shift Lock" { + !allowExplicit; + whichModState= locked; + modifiers= Shift; + }; + indicator "Group 2" { + !allowExplicit; + groups= 0xfe; + }; + indicator "Mouse Keys" { + indicatorDrivesKeyboard; + controls= mouseKeys; + }; +}; + +xkb_symbols "pc+us+inet(evdev)" { + + name[group1]="English (US)"; + + key { [ Escape ] }; + key { + symbols[Group1]= [ 1, exclam ], + symbols[Group2]= [ exclamdown, exclamdown ] + }; + key { [ 2, at ] }; + key { [ 3, numbersign ] }; + key { [ 4, dollar ] }; + key { [ 5, percent ] }; + key { [ 6, asciicircum ] }; + key { [ 7, ampersand ] }; + key { [ 8, asterisk ] }; + key { [ 9, parenleft ] }; + key { [ 0, parenright ] }; + key { [ minus, underscore ] }; + key { [ equal, plus ] }; + key { [ BackSpace, BackSpace ] }; + key { [ Tab, ISO_Left_Tab ] }; + key { + type= "ALPHABETIC", + symbols[Group1]= [ q, Q ] + }; + key { + type= "ALPHABETIC", + symbols[Group1]= [ w, W ] + }; + key { + type= "ALPHABETIC", + symbols[Group1]= [ e, E ], + symbols[Group2]= [ eacute, Eacute ] + }; + key { + type= "ALPHABETIC", + symbols[Group1]= [ r, R ] + }; + key { + type= "ALPHABETIC", + symbols[Group1]= [ t, T ] + }; + key { + type= "ALPHABETIC", + symbols[Group1]= [ y, Y ] + }; + key { + type= "ALPHABETIC", + symbols[Group1]= [ u, U ], + symbols[Group2]= [ uacute, Uacute ] + }; + key { + type= "ALPHABETIC", + symbols[Group1]= [ i, I ], + symbols[Group2]= [ iacute, Iacute ] + }; + key { + type= "ALPHABETIC", + symbols[Group1]= [ o, O ], + symbols[Group2]= [ oacute, Oacute ] + }; + key { + type= "ALPHABETIC", + symbols[Group1]= [ p, P ] + }; + key { [ bracketleft, braceleft ] }; + key { [ bracketright, braceright ] }; + key { [ Return ] }; + key { [ Control_L ] }; + key { + type= "ALPHABETIC", + symbols[Group1]= [ a, A ], + symbols[Group2]= [ aacute, Aacute ] + }; + key { + type= "ALPHABETIC", + symbols[Group1]= [ s, S ] + }; + key { + type= "ALPHABETIC", + symbols[Group1]= [ d, D ] + }; + key { + type= "ALPHABETIC", + symbols[Group1]= [ f, F ] + }; + key { + type= "ALPHABETIC", + symbols[Group1]= [ g, G ] + }; + key { + type= "ALPHABETIC", + symbols[Group1]= [ h, H ] + }; + key { + type= "ALPHABETIC", + symbols[Group1]= [ j, J ] + }; + key { + type= "ALPHABETIC", + symbols[Group1]= [ k, K ] + }; + key { + type= "ALPHABETIC", + symbols[Group1]= [ l, L ] + }; + key { [ semicolon, colon ] }; + key { [ apostrophe, quotedbl ] }; + key { [ grave, asciitilde ] }; + key { [ Shift_L ] }; + key { [ backslash, bar ] }; + key { + type= "ALPHABETIC", + symbols[Group1]= [ z, Z ] + }; + key { + type= "ALPHABETIC", + symbols[Group1]= [ x, X ] + }; + key { + type= "ALPHABETIC", + symbols[Group1]= [ c, C ] + }; + key { + type= "ALPHABETIC", + symbols[Group1]= [ v, V ] + }; + key { + type= "ALPHABETIC", + symbols[Group1]= [ b, B ] + }; + key { + type= "ALPHABETIC", + symbols[Group1]= [ n, N ], + symbols[Group2]= [ ntilde, Ntilde ] + }; + key { + type= "ALPHABETIC", + symbols[Group1]= [ m, M ] + }; + key { + symbols[Group1]= [ comma, less ], + symbols[Group2]= [ guillemotleft, guillemotleft ] + }; + key { + symbols[Group1]= [ period, greater ], + symbols[Group2]= [ guillemotright, guillemotright ] + }; + key { + symbols[Group1]= [ slash, question ], + symbols[Group2]= [ questiondown, questiondown ] + }; + key { [ Shift_R ] }; + key { + type= "CTRL+ALT", + symbols[Group1]= [ KP_Multiply, KP_Multiply, KP_Multiply, KP_Multiply, XF86ClearGrab ] + }; + key { [ Alt_L, Meta_L ] }; + key { [ space ] }; + key { [ Control_L ] }; + key { + type= "CTRL+ALT", + symbols[Group1]= [ F1, F1, F1, F1, XF86Switch_VT_1 ] + }; + key { + type= "CTRL+ALT", + symbols[Group1]= [ F2, F2, F2, F2, XF86Switch_VT_2 ] + }; + key { + type= "CTRL+ALT", + symbols[Group1]= [ F3, F3, F3, F3, XF86Switch_VT_3 ] + }; + key { + type= "CTRL+ALT", + symbols[Group1]= [ F4, F4, F4, F4, XF86Switch_VT_4 ] + }; + key { + type= "CTRL+ALT", + symbols[Group1]= [ F5, F5, F5, F5, XF86Switch_VT_5 ] + }; + key { + type= "CTRL+ALT", + symbols[Group1]= [ F6, F6, F6, F6, XF86Switch_VT_6 ] + }; + key { + type= "CTRL+ALT", + symbols[Group1]= [ F7, F7, F7, F7, XF86Switch_VT_7 ] + }; + key { + type= "CTRL+ALT", + symbols[Group1]= [ F8, F8, F8, F8, XF86Switch_VT_8 ] + }; + key { + type= "CTRL+ALT", + symbols[Group1]= [ F9, F9, F9, F9, XF86Switch_VT_9 ] + }; + key { + type= "CTRL+ALT", + symbols[Group1]= [ F10, F10, F10, F10, XF86Switch_VT_10 ] + }; + key { [ Num_Lock ] }; + key { [ Scroll_Lock ] }; + key { [ KP_Home, KP_7 ] }; + key { [ KP_Up, KP_8 ] }; + key { [ KP_Prior, KP_9 ] }; + key { + type= "CTRL+ALT", + symbols[Group1]= [ KP_Subtract, KP_Subtract, KP_Subtract, KP_Subtract, XF86Prev_VMode ] + }; + key { [ KP_Left, KP_4 ] }; + key { [ KP_Begin, KP_5 ] }; + key { [ KP_Right, KP_6 ] }; + key { + type= "CTRL+ALT", + symbols[Group1]= [ KP_Add, KP_Add, KP_Add, KP_Add, XF86Next_VMode ] + }; + key { [ KP_End, KP_1 ] }; + key { [ KP_Down, KP_2 ] }; + key { [ KP_Next, KP_3 ] }; + key { [ KP_Insert, KP_0 ] }; + key { [ KP_Delete, KP_Decimal ] }; + key { [ ISO_Level3_Shift ] }; + key { + type= "FOUR_LEVEL", + symbols[Group1]= [ less, greater, bar, brokenbar ] + }; + key { + type= "CTRL+ALT", + symbols[Group1]= [ F11, F11, F11, F11, XF86Switch_VT_11 ] + }; + key { + type= "CTRL+ALT", + symbols[Group1]= [ F12, F12, F12, F12, XF86Switch_VT_12 ] + }; + key { [ Katakana ] }; + key { [ Hiragana ] }; + key { [ Henkan_Mode ] }; + key { [ Hiragana_Katakana ] }; + key { [ Muhenkan ] }; + key { [ KP_Enter ] }; + key { [ Control_R ] }; + key { + type= "CTRL+ALT", + symbols[Group1]= [ KP_Divide, KP_Divide, KP_Divide, KP_Divide, XF86Ungrab ] + }; + key { + type= "PC_ALT_LEVEL2", + symbols[Group1]= [ Print, Sys_Req ] + }; + key { + type= "TWO_LEVEL", + symbols[Group1]= [ Multi_key, Multi_key ] + }; + key { [ Linefeed ] }; + key { [ Home ] }; + key { [ Up ] }; + key { [ Prior ] }; + key { [ Left ] }; + key { [ Right ] }; + key { [ End ] }; + key { [ Down ] }; + key { [ Next ] }; + key { [ Insert ] }; + key { [ Delete ] }; + key { [ XF86AudioMute ] }; + key { [ XF86AudioLowerVolume ] }; + key { [ XF86AudioRaiseVolume ] }; + key { [ XF86PowerOff ] }; + key { [ KP_Equal ] }; + key { [ plusminus ] }; + key { + type= "PC_CONTROL_LEVEL2", + symbols[Group1]= [ Pause, Break ] + }; + key { [ XF86LaunchA ] }; + key { [ KP_Decimal, KP_Decimal ] }; + key { [ Hangul ] }; + key { [ Hangul_Hanja ] }; + key { [ Super_L ] }; + key { [ Super_R ] }; + key { [ Menu ] }; + key { [ Cancel ] }; + key { [ Redo ] }; + key { [ SunProps ] }; + key { [ Undo ] }; + key { [ SunFront ] }; + key { [ XF86Copy ] }; + key { [ XF86Open ] }; + key { [ XF86Paste ] }; + key { [ Find ] }; + key { [ XF86Cut ] }; + key { [ Help ] }; + key { [ XF86MenuKB ] }; + key { [ XF86Calculator ] }; + key { [ XF86Sleep ] }; + key { [ XF86WakeUp ] }; + key { [ XF86Explorer ] }; + key { [ XF86Send ] }; + key { [ XF86Xfer ] }; + key { [ XF86Launch1 ] }; + key { [ XF86Launch2 ] }; + key { [ XF86WWW ] }; + key { [ XF86DOS ] }; + key { [ XF86ScreenSaver ] }; + key { [ XF86RotateWindows ] }; + key { [ XF86TaskPane ] }; + key { [ XF86Mail ] }; + key { [ XF86Favorites ] }; + key { [ XF86MyComputer ] }; + key { [ XF86Back ] }; + key { [ XF86Forward ] }; + key { [ XF86Eject ] }; + key { [ XF86Eject, XF86Eject ] }; + key { [ XF86AudioNext ] }; + key { [ XF86AudioPlay, XF86AudioPause ] }; + key { [ XF86AudioPrev ] }; + key { [ XF86AudioStop, XF86Eject ] }; + key { [ XF86AudioRecord ] }; + key { [ XF86AudioRewind ] }; + key { [ XF86Phone ] }; + key { [ XF86Tools ] }; + key { [ XF86HomePage ] }; + key { [ XF86Reload ] }; + key { [ XF86Close ] }; + key { [ XF86ScrollUp ] }; + key { [ XF86ScrollDown ] }; + key { [ parenleft ] }; + key { [ parenright ] }; + key { [ XF86New ] }; + key { [ Redo ] }; + key { [ XF86Tools ] }; + key { [ XF86Launch5 ] }; + key { [ XF86Launch6 ] }; + key { [ XF86Launch7 ] }; + key { [ XF86Launch8 ] }; + key { [ XF86Launch9 ] }; + key { [ XF86AudioMicMute ] }; + key { [ XF86TouchpadToggle ] }; + key { [ XF86TouchpadOn ] }; + key { [ XF86TouchpadOff ] }; + key { [ Mode_switch ] }; + key { [ NoSymbol, Alt_L ] }; + key { [ NoSymbol, Meta_L ] }; + key { [ NoSymbol, Super_L ] }; + key { [ NoSymbol, Hyper_L ] }; + key { [ XF86AudioPlay ] }; + key { [ XF86AudioPause ] }; + key { [ XF86Launch3 ] }; + key { [ XF86Launch4 ] }; + key { [ XF86LaunchB ] }; + key { [ XF86Suspend ] }; + key { [ XF86Close ] }; + key { [ XF86AudioPlay ] }; + key { [ XF86AudioForward ] }; + key { [ Print ] }; + key { [ XF86WebCam ] }; + key { [ XF86Mail ] }; + key { [ XF86Messenger ] }; + key { [ XF86Search ] }; + key { [ XF86Go ] }; + key { [ XF86Finance ] }; + key { [ XF86Game ] }; + key { [ XF86Shop ] }; + key { [ Cancel ] }; + key { [ XF86MonBrightnessDown ] }; + key { [ XF86MonBrightnessUp ] }; + key { [ XF86AudioMedia ] }; + key { [ XF86Display ] }; + key { [ XF86KbdLightOnOff ] }; + key { [ XF86KbdBrightnessDown ] }; + key { [ XF86KbdBrightnessUp ] }; + key { [ XF86Send ] }; + key { [ XF86Reply ] }; + key { [ XF86MailForward ] }; + key { [ XF86Save ] }; + key { [ XF86Documents ] }; + key { [ XF86Battery ] }; + key { [ XF86Bluetooth ] }; + key { [ XF86WLAN ] }; + key { [ NoSymbol ] }; + key { [ XF86WWAN ] }; + key { [ XF86RFKill ] }; + modifier_map Control { }; + modifier_map Shift { }; + modifier_map Shift { }; + modifier_map Mod1 { }; + modifier_map Control { }; + modifier_map Mod2 { }; + modifier_map Mod5 { }; + modifier_map Control { }; + modifier_map Mod1 { }; + modifier_map Mod4 { }; + modifier_map Mod4 { }; + modifier_map Mod5 { }; + modifier_map Mod1 { }; + modifier_map Mod4 { }; + modifier_map Mod4 { }; +}; + +xkb_geometry "pc(pc105)" { + + width= 470; + height= 180; + + alias = ; + alias = ; + + baseColor= "white"; + labelColor= "black"; + xfont= "-*-helvetica-medium-r-normal--*-120-*-*-*-*-iso8859-1"; + description= "Generic 105"; + + shape "NORM" { + corner= 1, + { [ 18, 18 ] }, + { [ 2, 1 ], [ 16, 16 ] } + }; + shape "BKSP" { + corner= 1, + { [ 38, 18 ] }, + { [ 2, 1 ], [ 36, 16 ] } + }; + shape "TABK" { + corner= 1, + { [ 28, 18 ] }, + { [ 2, 1 ], [ 26, 16 ] } + }; + shape "BKSL" { + corner= 1, + { [ 28, 18 ] }, + { [ 2, 1 ], [ 26, 16 ] } + }; + shape "RTRN" { + corner= 1, + { [ 0, 0 ], [ 28, 0 ], [ 28, 37 ], [ 5, 37 ], + [ 5, 18 ], [ 0, 18 ] }, + { [ 2, 1 ], [ 26, 1 ], [ 26, 35 ], [ 7, 35 ], + [ 7, 16 ], [ 2, 16 ] }, + approx= { [ 5, 0 ], [ 28, 37 ] } + }; + shape "CAPS" { + corner= 1, + { [ 33, 18 ] }, + { [ 2, 1 ], [ 31, 16 ] } + }; + shape "LFSH" { + corner= 1, + { [ 25, 18 ] }, + { [ 2, 1 ], [ 23, 16 ] } + }; + shape "RTSH" { + corner= 1, + { [ 50, 18 ] }, + { [ 2, 1 ], [ 48, 16 ] } + }; + shape "MODK" { + corner= 1, + { [ 27, 18 ] }, + { [ 2, 1 ], [ 25, 16 ] } + }; + shape "SMOD" { + corner= 1, + { [ 23, 18 ] }, + { [ 2, 1 ], [ 21, 16 ] } + }; + shape "SPCE" { + corner= 1, + { [ 113, 18 ] }, + { [ 2, 1 ], [ 111, 16 ] } + }; + shape "KP0" { + corner= 1, + { [ 37, 18 ] }, + { [ 2, 1 ], [ 35, 16 ] } + }; + shape "KPAD" { + corner= 1, + { [ 18, 37 ] }, + { [ 2, 1 ], [ 16, 35 ] } + }; + shape "LEDS" { { [ 75, 20 ] } }; + shape "LED" { { [ 5, 1 ] } }; + section "Function" { + key.color= "grey20"; + priority= 7; + top= 22; + left= 19; + width= 351; + height= 19; + row { + top= 1; + left= 1; + keys { + { , "NORM", 1 }, + { , "NORM", 20, color="white" }, + { , "NORM", 1, color="white" }, + { , "NORM", 1, color="white" }, + { , "NORM", 1, color="white" }, + { , "NORM", 11, color="white" }, + { , "NORM", 1, color="white" }, + { , "NORM", 1, color="white" }, + { , "NORM", 1, color="white" }, + { , "NORM", 11, color="white" }, + { , "NORM", 1, color="white" }, + { , "NORM", 1, color="white" }, + { , "NORM", 1, color="white" }, + { , "NORM", 8, color="white" }, + { , "NORM", 1, color="white" }, + { , "NORM", 1, color="white" } + }; + }; + }; // End of "Function" section + + section "Alpha" { + key.color= "white"; + priority= 8; + top= 61; + left= 19; + width= 287; + height= 95; + row { + top= 1; + left= 1; + keys { + { , "NORM", 1 }, { , "NORM", 1 }, + { , "NORM", 1 }, { , "NORM", 1 }, + { , "NORM", 1 }, { , "NORM", 1 }, + { , "NORM", 1 }, { , "NORM", 1 }, + { , "NORM", 1 }, { , "NORM", 1 }, + { , "NORM", 1 }, { , "NORM", 1 }, + { , "NORM", 1 }, + { , "BKSP", 1, color="grey20" } + }; + }; + row { + top= 20; + left= 1; + keys { + { , "TABK", 1, color="grey20" }, + { , "NORM", 1 }, { , "NORM", 1 }, + { , "NORM", 1 }, { , "NORM", 1 }, + { , "NORM", 1 }, { , "NORM", 1 }, + { , "NORM", 1 }, { , "NORM", 1 }, + { , "NORM", 1 }, { , "NORM", 1 }, + { , "NORM", 1 }, { , "NORM", 1 }, + { , "RTRN", 1, color="grey20" } + }; + }; + row { + top= 39; + left= 1; + keys { + { , "CAPS", 1, color="grey20" }, + { , "NORM", 1 }, { , "NORM", 1 }, + { , "NORM", 1 }, { , "NORM", 1 }, + { , "NORM", 1 }, { , "NORM", 1 }, + { , "NORM", 1 }, { , "NORM", 1 }, + { , "NORM", 1 }, { , "NORM", 1 }, + { , "NORM", 1 }, { , "NORM", 1 } + }; + }; + row { + top= 58; + left= 1; + keys { + { , "LFSH", 1, color="grey20" }, + { , "NORM", 1 }, { , "NORM", 1 }, + { , "NORM", 1 }, { , "NORM", 1 }, + { , "NORM", 1 }, { , "NORM", 1 }, + { , "NORM", 1 }, { , "NORM", 1 }, + { , "NORM", 1 }, { , "NORM", 1 }, + { , "NORM", 1 }, + { , "RTSH", 1, color="grey20" } + }; + }; + row { + top= 77; + left= 1; + keys { + { , "MODK", 1, color="grey20" }, + { , "SMOD", 1, color="grey20" }, + { , "SMOD", 1, color="grey20" }, + { , "SPCE", 1 }, + { , "SMOD", 1, color="grey20" }, + { , "SMOD", 1, color="grey20" }, + { , "SMOD", 1, color="grey20" }, + { , "SMOD", 1, color="grey20" } + }; + }; + }; // End of "Alpha" section + + section "Editing" { + key.color= "grey20"; + priority= 9; + top= 61; + left= 312; + width= 58; + height= 95; + row { + top= 1; + left= 1; + keys { + { , "NORM", 1 }, { , "NORM", 1 }, + { , "NORM", 1 } + }; + }; + row { + top= 20; + left= 1; + keys { + { , "NORM", 1 }, { , "NORM", 1 }, + { , "NORM", 1 } + }; + }; + row { + top= 58; + left= 20; + keys { + { , "NORM", 1 } + }; + }; + row { + top= 77; + left= 1; + keys { + { , "NORM", 1 }, { , "NORM", 1 }, + { , "NORM", 1 } + }; + }; + }; // End of "Editing" section + + section "Keypad" { + key.color= "grey20"; + priority= 10; + top= 61; + left= 376; + width= 77; + height= 95; + row { + top= 1; + left= 1; + keys { + { , "NORM", 1 }, { , "NORM", 1 }, + { , "NORM", 1 }, { , "NORM", 1 } + }; + }; + row { + top= 20; + left= 1; + keys { + { , "NORM", 1, color="white" }, + { , "NORM", 1, color="white" }, + { , "NORM", 1, color="white" }, + { , "KPAD", 1 } + }; + }; + row { + top= 39; + left= 1; + keys { + { , "NORM", 1, color="white" }, + { , "NORM", 1, color="white" }, + { , "NORM", 1, color="white" } + }; + }; + row { + top= 58; + left= 1; + keys { + { , "NORM", 1, color="white" }, + { , "NORM", 1, color="white" }, + { , "NORM", 1, color="white" }, + { , "KPAD", 1 } + }; + }; + row { + top= 77; + left= 1; + keys { + { , "KP0", 1, color="white" }, + { , "NORM", 1, color="white" } + }; + }; + }; // End of "Keypad" section + + solid "LedPanel" { + top= 22; + left= 377; + priority= 0; + color= "grey10"; + shape= "LEDS"; + }; + indicator "Num Lock" { + top= 37; + left= 382; + priority= 1; + onColor= "green"; + offColor= "green30"; + shape= "LED"; + }; + indicator "Caps Lock" { + top= 37; + left= 407; + priority= 2; + onColor= "green"; + offColor= "green30"; + shape= "LED"; + }; + indicator "Scroll Lock" { + top= 37; + left= 433; + priority= 3; + onColor= "green"; + offColor= "green30"; + shape= "LED"; + }; + text "NumLockLabel" { + top= 25; + left= 378; + priority= 4; + width= 19.8; + height= 10; + XFont= "-*-helvetica-medium-r-normal--*-120-*-*-*-*-iso8859-1"; + text= "Num\nLock"; + }; + text "CapsLockLabel" { + top= 25; + left= 403; + priority= 5; + width= 26.4; + height= 10; + XFont= "-*-helvetica-medium-r-normal--*-120-*-*-*-*-iso8859-1"; + text= "Caps\nLock"; + }; + text "ScrollLockLabel" { + top= 25; + left= 428; + priority= 6; + width= 39.6; + height= 10; + XFont= "-*-helvetica-medium-r-normal--*-120-*-*-*-*-iso8859-1"; + text= "Scroll\nLock"; + }; +}; + +};