diff --git a/src/wm.c b/src/wm.c index 822346a..b436a92 100644 --- a/src/wm.c +++ b/src/wm.c @@ -165,6 +165,28 @@ bool wm_window_is_dock(Wm *wm, Window w) return false; } +void wm_node_set_up_tab(Wm *wm, TreeNode *node, Client *client) +{ + assert(node); + assert(client); + + node->type = NODE_TAB; + node->client = NULL; + assert(node->children->size == 0); + node->tab_frame = XCreateSimpleWindow(wm->display, wm->root.window, + node->pos.x, node->pos.y, node->pos.w, node->pos.h, 0, 0, 0); + + XReparentWindow(wm->display, client->frame, node->tab_frame, 0, 0); + XMapWindow(wm->display, node->tab_frame); + + TreeNode *client_new_node = wm_treenode_new(NODE_CLIENT, node); + wm_treenode_add_child(node, client_new_node); + client_new_node->client = client; + client_new_node->pos = node->pos; + wm_client_focus(wm, client); + client->focused = true; +} + NodeType wm_split_to_nodetype(SplitMode mode) { switch (mode) { @@ -181,6 +203,18 @@ NodeType wm_split_to_nodetype(SplitMode mode) } } +static uint64_t simple_update_cost_function(TreeNode* node1, TreeNode* node2) +{ + if (node1->type != node2->type) return 10; + + if (node1->type != NODE_CLIENT) return 0; + + if (strcmp(node1->client->name, node2->client->name) == 0) + return 0; + else + return 10; +} + void wm_ws_tree_insert_client(Wm *wm, Workspace *ws, Client *client) { DEBUG_PRINT("%s\n", __func__); @@ -194,6 +228,12 @@ void wm_ws_tree_insert_client(Wm *wm, Workspace *ws, Client *client) } if (wm_treenode_is_empty(ws->tree) && ws->tree->client == NULL) { + + if (ws->split == SPLIT_TAB) { + wm_node_set_up_tab(wm, ws->tree, client); + return; + } + ws->tree->type = NODE_CLIENT; ws->tree->client = client; ws->tree->pos = (Rect) { @@ -204,10 +244,22 @@ void wm_ws_tree_insert_client(Wm *wm, Workspace *ws, Client *client) return; } + wm_treenode_print(CURRENT_WS(wm).tree); + TreeNode *focused_node = ws->focused_node ? ws->focused_node : wm_treenode_ptr_find_focused_client_node(ws->tree); assert(focused_node); + if (focused_node->parent && focused_node->parent->type == NODE_TAB) { + TreeNode *child = wm_treenode_new(NODE_CLIENT, focused_node->parent); + child->pos = focused_node->pos; + child->client = client; + XReparentWindow(wm->display, client->frame, focused_node->parent->tab_frame, 0, 0); + wm_nodearray_push(focused_node->parent->children, child); + wm_client_focus(wm, client); + return; + } + Client *old_client = focused_node->client; focused_node->type = wm_split_to_nodetype(ws->split); @@ -228,18 +280,29 @@ void wm_switch_ws(Wm *wm, size_t ws) if (ws > wm->selected_monitor->wscount) return; - int wscc = 0; Client *c; DEBUG_PRINT("switching to ws %ld, clients:", ws); wm_treenode_print(wm->selected_monitor->workspaces[ws].tree); NodeArray *current_ws_clients = wm_treenode_find_client_nodes(CURRENT_WS(wm).tree); + DEBUG_PRINT("current ws clients: %ld\n", current_ws_clients->size); for (size_t i = 0; i < current_ws_clients->size; i++) { c = ((TreeNode**)current_ws_clients->nodes)[i]->client; assert(c); if (c->ws->index == wm->selected_monitor->selected_ws) { + TreeNode *node = wm_treenode_ptr_find_client_node(c->ws->tree, c); + if (node && node->parent && node->parent->type == NODE_TAB) { + DEBUG_PRINT("tab_frame %ld\n", node->parent->tab_frame); + XWindowAttributes att; + XGetWindowAttributes(wm->display, node->parent->tab_frame, &att); + if (att.map_state == IsUnmapped) continue; + + XUnmapWindow(wm->display, node->parent->tab_frame); + XSync(wm->display, False); + } + DEBUG_PRINT("wm_switch_ws hide client selws: %ld\n", c->ws->index) wm_client_hide(wm, c); } @@ -251,17 +314,22 @@ void wm_switch_ws(Wm *wm, size_t ws) (unsigned char*) &(ws), XA_CARDINAL, 1); NodeArray *switch_ws_clients = wm_treenode_find_client_nodes(CURRENT_WS(wm).tree); + NodeArray *mapped_tab_nodes = wm_nodearray_new(); for (size_t i = 0; i < switch_ws_clients->size; i++) { - c = ((TreeNode**)switch_ws_clients->nodes)[i]->client; - if (c->ws->index == wm->selected_monitor->selected_ws) { - wscc++; + TreeNode *node = switch_ws_clients->nodes[i]; + c = node->client; + if (c->ws->index != wm->selected_monitor->selected_ws) continue; + + if (node->parent && node->parent->type == NODE_TAB && + !wm_nodearray_contains(mapped_tab_nodes, node->parent)) { + XMapWindow(wm->display, node->parent->tab_frame); + XSync(wm->display, False); + } else { wm_client_show(wm, c); } } - DEBUG_PRINT("wm_switch_ws focused ws client count: %d\n", wscc); - if (CURRENT_WS(wm).focused_node) wm_client_focus(wm, CURRENT_WS(wm).focused_node->client); @@ -311,6 +379,39 @@ void wm_layout(Wm *wm, Monitor *m) Client *client = node->client; assert(client); + if (client->ws->index != m->selected_ws) continue; + + if (node->parent && node->parent->type == NODE_TAB) { + for (size_t j = 0; j < node->parent->children->size; j++) { + TreeNode *child_node = node->parent->children->nodes[j]; + + child_node->client->x = node->pos.x; + child_node->client->y = node->pos.y; + child_node->client->w = node->pos.w; + child_node->client->h = node->pos.h; + + unsigned int value_mask = CWX | CWY | CWWidth | CWHeight; + XWindowChanges xwc = wm_client_to_xwchanges(child_node->client); + xwc.y = wm->titlebar_font->height * 2; + xwc.x = 0; + xwc.height -= wm->titlebar_font->height * 2; + XConfigureWindow(wm->display, child_node->client->frame, value_mask, &xwc); + xwc.y = 0; + xwc.x = 0; + XConfigureWindow(wm->display, child_node->client->window, value_mask, &xwc); + + if (wm_client_is_focused(wm, child_node->client)) { + wm_client_show(wm, child_node->client); + } else { + wm_client_hide(wm, child_node->client); + } + XSync(wm->display, False); + } + + wm_monitor_draw_all_clients_frame(wm, client->m); + continue; + } + client->x = node->pos.x; client->y = node->pos.y; client->w = node->pos.w; @@ -396,6 +497,8 @@ void wm_mainloop(Wm *wm) case MapRequest: DEBUG_PRINT("MapRequest: %d\n", (int)e.xmaprequest.window) wm_maprequest_handler(wm, e.xmaprequest); + case UnmapNotify: + DEBUG_PRINT("UnmapNotify: %d\n", (int)e.xmaprequest.window) break; default: DEBUG_PRINT("default: %d\n", e.type); @@ -431,9 +534,6 @@ void wm_init(Wm *wm) char *display_string = DisplayString(wm->display); setenv("DISPLAY", display_string, 1); - // TODO: only testing - // wm_socket_init(); - wm->root.window = XRootWindow(wm->display, DefaultScreen(wm->display)); DEBUG_PRINT("root window: %ld\n", wm->root.window); @@ -508,9 +608,6 @@ void wm_exit(Wm *wm) XUngrabKey(wm->display, AnyKey, AnyModifier, wm->root.window); - // TODO: perhaps add created clients to a PtrArray field in workspace. - // would reduce number of calls to wm_treenode_find_client_nodes_ptr - for (size_t i = 0; i < wm->monitors_len; i++) { for (size_t j = 0; j < wm->monitors[i].wscount; j++) { NodeArray *clients = wm_treenode_find_client_nodes( @@ -585,7 +682,7 @@ void wm_kb_spawn(Wm *wm, Arg *args) DEBUG_PRINT("args sl 0: %s\n", args->sl[0]) DEBUG_PRINT("args count: %d\n", args->count) - WM_LOG_STATE_START(wm); + // WM_LOG_STATE_START(wm); if (args->sl[args->count-1] != NULL) { fprintf(stderr, "%s recieved non null-terminated args. Returning\n", @@ -615,7 +712,7 @@ void wm_kb_exit(Wm* wm, Arg *args) void wm_kb_kill(Wm *wm, Arg *args) { - WM_LOG_STATE_START(wm); + // WM_LOG_STATE_START(wm); Client *c; @@ -631,18 +728,18 @@ void wm_kb_switch_ws(Wm *wm, Arg *args) { RETURN_IF_NULL(args) - WM_LOG_STATE_START(wm); + // WM_LOG_STATE_START(wm); wm_switch_ws(wm, args->i); - WM_LOG_STATE_END(wm); + // WM_LOG_STATE_END(wm); } void wm_kb_move_client_ws(Wm *wm, Arg *args) { RETURN_IF_NULL(args) - WM_LOG_STATE_START(wm); + // WM_LOG_STATE_START(wm); wm_move_client_ws(wm, args->i); @@ -654,13 +751,13 @@ void wm_kb_focus_dir(Wm *wm, Arg *args) Client *c; RETURN_IF_NULL(args) - WM_LOG_STATE_START(wm); + // WM_LOG_STATE_START(wm); c = wm_client_get_focused(wm); wm_client_focus_dir(wm, c, args->i); - WM_LOG_STATE_END(wm); + // WM_LOG_STATE_END(wm); } void wm_kb_move_dir(Wm *wm, Arg *args) @@ -668,7 +765,7 @@ void wm_kb_move_dir(Wm *wm, Arg *args) Client *c; RETURN_IF_NULL(args) - WM_LOG_STATE_START(wm); + // WM_LOG_STATE_START(wm); c = wm_client_get_focused(wm); @@ -679,95 +776,24 @@ void wm_kb_move_dir(Wm *wm, Arg *args) void wm_kb_switch_split_mode(Wm *wm, Arg *args) { + DEBUG_PRINT("%s\n", __func__); RETURN_IF_NULL(args) - WM_LOG_STATE_START(wm); + // WM_LOG_STATE_START(wm); - wm->selected_monitor->workspaces[wm->selected_monitor->selected_ws].split = args->i; + CURRENT_WS(wm).split = args->i; - WM_LOG_STATE_END(wm); -} - -struct sockaddr wm_socket_init(Wm *wm) -{ - struct sockaddr_un sock_addr; - int ret; - - ret = wm->socket_fd = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0); - - if (ret == -1) { - fprintf(stderr, "wm: could not create socket. Exiting.\n"); - exit(EXIT_FAILURE); - } - - sock_addr.sun_family = AF_UNIX; - - snprintf(sock_addr.sun_path, sizeof(sock_addr.sun_path), - "/tmp/wm_socket_%c", DisplayString(wm->display)[1]); - - ret = bind(wm->socket_fd, (struct sockaddr *) &sock_addr, sizeof(sock_addr)); - - if (ret == -1) { - fprintf(stderr, "wm: could not bind to socket. Exiting.\n"); - exit(EXIT_FAILURE); - } - - ret = listen(wm->socket_fd, 512); - - if (ret == -1) { - fprintf(stderr, "wm: could not listen to socket. Exiting.\n"); - exit(EXIT_FAILURE); - } -} - -void wm_socket_cleanup(Wm *wm) -{ - struct sockaddr s; - socklen_t t = 108; - getsockname(wm->socket_fd, &s, &t); - DEBUG_PRINT("socket cleanup path: %s\n", s.sa_data) - remove(s.sa_data); -} - -void wm_sigint_handler(Wm *wm, int signum) -{ - wm_socket_cleanup(wm); - exit(1); -} - -// TODO: maybe move some parts to wmc -void wm_settings_message_parse(Wm *wm, char *c, int len) -{ - if (len <= 0) - return; - - int op; /* 0 = set, 1 = get */ - size_t i = 0; - char *token; - char tokens[20][50]; - char *settings[] = {"border-width", "border-color", "focused-border-color", - "msfact", "focus-on-motion"}; - - while((token = strtok(c, " ")) != NULL) { - DEBUG_PRINT("message_parse token: %s\n", token) - strncpy(tokens[i], token, 50); - } - - if (strcmp(tokens[1], "set") == 0) { - op = 0; - } else if (strcmp(c, "get") == 0) { - op = 1; - } else { - return; - } - - for (i = 0; i < sizeof(settings)/sizeof(char*); i++) { - if (strcmp(tokens[1], settings[i])) { - if (op == 1) { - // wm_settings_get(settings[i], &ret); - } else { - // wm_settings_set(settings[i]); - } - } - } + if (args->i == SPLIT_TAB) { + TreeNode *focused_node = CURRENT_WS(wm).focused_node ? CURRENT_WS(wm).focused_node : + wm_treenode_ptr_find_focused_client_node(CURRENT_WS(wm).tree); + + if (!focused_node) return; + if (focused_node->parent && focused_node->parent->type == NODE_TAB) return; + + Client *client = focused_node->client; + wm_node_set_up_tab(wm, focused_node, client); + wm_layout(wm, CURRENT_WS(wm).monitor); + } + + // WM_LOG_STATE_END(wm); } diff --git a/src/wm.h b/src/wm.h index 36fea10..a85ed8b 100644 --- a/src/wm.h +++ b/src/wm.h @@ -20,6 +20,7 @@ along with this program. If not, see . #ifndef WM_H #define WM_H +#include #include #include #include @@ -40,17 +41,10 @@ along with this program. If not, see . #include "config.h" #include "util.h" -// TODO: when only 1 window on ws it is not focused -// TODO: dont draw border on not normal windows, floating dialog window, -// window type/name/... atom member variable on Client struct -// TODO: get_atom probably not working correctly -// TODO: important: code cleanliness, ewmh!! -// TODO: config command line utility(sockets), maybe avoid global vars - #define RETURN_IF_NULL(c) \ if (c == NULL) \ { \ - fprintf(stderr, "wm: variable %s was null in function %s\n", #c, __func__); \ + DEBUG_PRINT("wm: variable %s was null in function %s\n", #c, __func__); \ return; \ } @@ -149,6 +143,7 @@ void wm_mstack(Wm *wm, Monitor *m); void wm_set_layout(Wm *wm, void(*f)(Wm *wm, Monitor*)); void wm_layout(Wm *wm, Monitor *m); bool wm_window_is_dock(Wm* wm, Window w); +void wm_node_set_up_tab(Wm *wm, TreeNode *node, Client *client); NodeType wm_split_to_nodetype(SplitMode mode); void wm_ws_tree_insert_client(Wm *wm, Workspace *ws, Client *client); @@ -171,10 +166,4 @@ void wm_kb_move_dir(Wm *wm, Arg *args); void wm_kb_exit(Wm* wm, Arg *args); void wm_kb_switch_split_mode(Wm *wm, Arg *args); -struct sockaddr wm_socket_init(Wm *wm); -void wm_socket_cleanup(Wm *wm); -void wm_settings_message_parse(Wm *wm, char *c, int len); - -void wm_sigint_handler(Wm *wm, int signum); - #endif