void client_set_floating(Client* client, bool state) { client->floating = state; Frame* frame = get_current_monitor()->tag->frame; frame = frame_descend(frame); size_t floatcount = frame->content.clients.floatcount; floatcount += state ? 1 : -1; frame->content.clients.floatcount = floatcount; if(state) client_center(client, find_monitor_with_tag(client->tag)); monitor_apply_layout(find_monitor_with_tag(client->tag)); }
Client* manage_client(Window win) { if (get_client_from_window(win)) return NULL; // init client Client* client = create_client(); Monitor* m = get_current_monitor(); // set to window properties client->window = win; client_update_title(client); // apply rules int manage = 1; rules_apply(client, &manage); if (!manage) { destroy_client(client); // map it... just to be sure XMapWindow(gDisplay, win); return NULL; } unsigned int border, depth; Window root_win; int x, y; unsigned int w, h; XGetGeometry(gDisplay, win, &root_win, &x, &y, &w, &h, &border, &depth); // treat wanted coordinates as floating coords XRectangle size = client->float_size; size.width = w; size.height = h; size.x = m->rect.x + m->rect.width/2 - size.width/2; size.y = m->rect.y + m->rect.height/2 - size.height/2 + bar_height; client->float_size = size; client->last_size = size; XMoveResizeWindow(gDisplay, client->window, size.x, size.y, size.width, size.height); // actually manage it g_array_append_val(g_clients, client); XSetWindowBorderWidth(gDisplay, win, window_border_width); // insert to layout if (!client->tag) client->tag = m->tag; // get events from window client_update_wm_hints(client); XSelectInput(gDisplay, win, CLIENT_EVENT_MASK); window_grab_button(win); frame_insert_window(client->tag->frame, win); monitor_apply_layout(find_monitor_with_tag(client->tag)); return client; }
int load_command(int argc, char** argv, GString* output) { // usage: load TAG LAYOUT HSTag* tag = NULL; if (argc < 2) { return HERBST_NEED_MORE_ARGS; } char* layout_string = argv[1]; if (argc >= 3) { tag = find_tag(argv[1]); layout_string = argv[2]; if (!tag) { g_string_append_printf(output, "%s: Tag \"%s\" not found\n", argv[0], argv[1]); return HERBST_INVALID_ARGUMENT; } } else { // use current tag HSMonitor* m = get_current_monitor(); tag = m->tag; } assert(tag != NULL); char* rest = load_frame_tree(tag->frame, layout_string, output); if (output->len > 0) { g_string_prepend(output, "load: "); } tag_set_flags_dirty(); // we probably changed some window positions // arrange monitor HSMonitor* m = find_monitor_with_tag(tag); if (m) { frame_show_recursive(tag->frame); if (get_current_monitor() == m) { frame_focus_recursive(tag->frame); } monitor_apply_layout(m); } else { frame_hide_recursive(tag->frame); } if (!rest) { g_string_append_printf(output, "%s: Error while parsing!\n", argv[0]); return HERBST_INVALID_ARGUMENT; } if (rest[0] != '\0') { // if string was not parsed completely g_string_append_printf(output, "%s: Layout description was too long\n", argv[0]); g_string_append_printf(output, "%s: \"%s\" has not been parsed\n", argv[0], rest); return HERBST_INVALID_ARGUMENT; } return 0; }
void mouse_stop_drag() { if (g_win_drag_client) { client_set_dragged(g_win_drag_client, false); // resend last size monitor_apply_layout(g_drag_monitor); } g_win_drag_client = NULL; g_drag_function = NULL; XUngrabPointer(g_display, CurrentTime); // remove all enternotify-events from the event queue that were // generated by the XUngrabPointer XEvent ev; XSync(g_display, False); while(XCheckMaskEvent(g_display, EnterWindowMask, &ev)); }
void event_on_configure(XEvent event) { XConfigureRequestEvent* cre = &event.xconfigurerequest; HSClient* client = get_client_from_window(cre->window); XConfigureEvent ce; ce.type = ConfigureNotify; ce.display = g_display; ce.event = cre->window; ce.window = cre->window; if (client) { bool changes = false; if (client->sizehints && !client->dragged) { cre->width += 2*cre->border_width - 2*client->last_border_width; cre->height += 2*cre->border_width - 2*client->last_border_width; if (client->float_size.width != cre->width) changes = true; if (client->float_size.height != cre->height) changes = true; client->float_size.width = cre->width; client->float_size.height = cre->height; ce.x = client->last_size.x; ce.y = client->last_size.y; ce.width = client->last_size.width; ce.height = client->last_size.height; ce.override_redirect = False; ce.border_width = cre->border_width; ce.above = cre->above; } if (changes && client->tag->floating) { client_resize_floating(client, find_monitor_with_tag(client->tag)); } else if (changes && client->pseudotile) { monitor_apply_layout(find_monitor_with_tag(client->tag)); } else { // FIXME: why send event and not XConfigureWindow or XMoveResizeWindow?? XSendEvent(g_display, cre->window, False, StructureNotifyMask, (XEvent*)&ce); } } else { // if client not known.. then allow configure. // its probably a nice conky or dzen2 bar :) XWindowChanges wc; wc.x = cre->x; wc.y = cre->y; wc.width = cre->width; wc.height = cre->height; wc.border_width = cre->border_width; wc.sibling = cre->above; wc.stack_mode = cre->detail; XConfigureWindow(g_display, cre->window, cre->value_mask, &wc); } }
void client_set_fullscreen(Client* client, bool state) { if (client->fullscreen == state) return; client->fullscreen = state; if (state) { XChangeProperty(gDisplay, client->window, g_netatom[NetWmState], XA_ATOM, 32, PropModeReplace, (unsigned char *)&g_netatom[NetWmStateFullscreen], 1); XRaiseWindow(gDisplay, client->window); } else { XChangeProperty(gDisplay, client->window, g_netatom[NetWmState], XA_ATOM, 32, PropModeReplace, (unsigned char *)0, 0); } monitor_apply_layout(find_monitor_with_tag(client->tag)); }
void event_on_configure(XEvent event) { XConfigureRequestEvent* cre = &event.xconfigurerequest; HSClient* client = get_client_from_window(cre->window); if (client) { bool changes = false; Rectangle newRect = client->float_size; if (client->sizehints_floating && (is_client_floated(client) || client->pseudotile)) { bool width_requested = 0 != (cre->value_mask & CWWidth); bool height_requested = 0 != (cre->value_mask & CWHeight); bool x_requested = 0 != (cre->value_mask & CWX); bool y_requested = 0 != (cre->value_mask & CWY); cre->width += 2*cre->border_width; cre->height += 2*cre->border_width; if (width_requested && newRect.width != cre->width) changes = true; if (height_requested && newRect.height != cre->height) changes = true; if (x_requested || y_requested) changes = true; if (x_requested) newRect.x = cre->x; if (y_requested) newRect.y = cre->y; if (width_requested) newRect.width = cre->width; if (height_requested) newRect.height = cre->height; } if (changes && is_client_floated(client)) { client->float_size = newRect; client_resize_floating(client, find_monitor_with_tag(client->tag)); } else if (changes && client->pseudotile) { client->float_size = newRect; monitor_apply_layout(find_monitor_with_tag(client->tag)); } else { // FIXME: why send event and not XConfigureWindow or XMoveResizeWindow?? client_send_configure(client); } } else { // if client not known.. then allow configure. // its probably a nice conky or dzen2 bar :) XWindowChanges wc; wc.x = cre->x; wc.y = cre->y; wc.width = cre->width; wc.height = cre->height; wc.border_width = cre->border_width; wc.sibling = cre->above; wc.stack_mode = cre->detail; XConfigureWindow(g_display, cre->window, cre->value_mask, &wc); } }
void unmanage_client(Window win) { Client* client = get_client_from_window(win); if (!client) return; // remove from tag frame_remove_window(client->tag->frame, win); // and arrange monitor Monitor* m = find_monitor_with_tag(client->tag); if (m) monitor_apply_layout(m); // ignore events from it XSelectInput(gDisplay, win, 0); XUngrabButton(gDisplay, AnyButton, AnyModifier, win); // permanently remove it for(int i=0; i<g_clients->len; i++){ if(g_array_index(g_clients, Client*, i) == client) g_array_remove_index(g_clients, i); } }
void client_set_fullscreen(HSClient* client, bool state) { client->fullscreen = state; if (client->ewmhnotify) { client->ewmhfullscreen = state; } HSStack* stack = client->tag->stack; if (state) { stack_slice_add_layer(stack, client->slice, LAYER_FULLSCREEN); } else { stack_slice_remove_layer(stack, client->slice, LAYER_FULLSCREEN); } tag_update_focus_layer(client->tag); monitor_apply_layout(find_monitor_with_tag(client->tag)); char buf[STRING_BUF_SIZE]; snprintf(buf, STRING_BUF_SIZE, "0x%lx", client->window); ewmh_update_window_state(client); hook_emit_list("fullscreen", state ? "on" : "off", buf, NULL); }
void propertynotify(XEvent* event) { // printf("name is: PropertyNotify\n"); XPropertyEvent *ev = &event->xproperty; HSClient* client; if (ev->state == PropertyNewValue) { if (is_ipc_connectable(event->xproperty.window)) { ipc_handle_connection(event->xproperty.window); } else if((client = get_client_from_window(ev->window))) { if (ev->atom == XA_WM_HINTS) { client_update_wm_hints(client); } else if (ev->atom == XA_WM_NORMAL_HINTS) { updatesizehints(client); HSMonitor* m = find_monitor_with_tag(client->tag); if (m) monitor_apply_layout(m); } else if (ev->atom == XA_WM_NAME || ev->atom == g_netatom[NetWmName]) { client_update_title(client); } } } }
void unmanage_client(Window win) { HSClient* client = get_client_from_window(win); if (!client) { return; } if (client->dragged) { mouse_stop_drag(); } // remove from tag frame_remove_window(client->tag->frame, win); // ignore events from it XSelectInput(g_display, win, 0); //XUngrabButton(g_display, AnyButton, AnyModifier, win); // permanently remove it HSTag* tag = client->tag; g_hash_table_remove(g_clients, &win); // and arrange monitor after the client has been removed from the stack HSMonitor* m = find_monitor_with_tag(tag); tag_update_focus_layer(tag); if (m) monitor_apply_layout(m); ewmh_remove_client(win); tag_set_flags_dirty(); }
void client_set_pseudotile(HSClient* client, bool state) { client->pseudotile = state; monitor_apply_layout(find_monitor_with_tag(client->tag)); }
HSClient* manage_client(Window win) { if (is_herbstluft_window(g_display, win)) { // ignore our own window return NULL; } if (get_client_from_window(win)) { return NULL; } // init client HSClient* client = create_client(); client->pid = window_pid(g_display, win); HSMonitor* m = get_current_monitor(); // set to window properties client->window = win; client_update_title(client); unsigned int border, depth; Window root_win; int x, y; unsigned int w, h; XGetGeometry(g_display, win, &root_win, &x, &y, &w, &h, &border, &depth); // treat wanted coordinates as floating coords client->float_size.x = x; client->float_size.y = y; client->float_size.width = w; client->float_size.height = h; // apply rules HSClientChanges changes; client_changes_init(&changes, client); rules_apply(client, &changes); if (changes.tag_name) { client->tag = find_tag(changes.tag_name->str); } if (!changes.manage) { client_changes_free_members(&changes); client_destroy(client); // map it... just to be sure XMapWindow(g_display, win); return NULL; } // actually manage it g_hash_table_insert(g_clients, &(client->window), client); client->window_str = g_string_sized_new(10); g_string_printf(client->window_str, "0x%lx", win); hsobject_link(g_client_object, &client->object, client->window_str->str); // insert to layout if (!client->tag) { client->tag = m->tag; } // get events from window XSelectInput(g_display, win, CLIENT_EVENT_MASK); // insert window to the stack client->slice = slice_create_client(client); stack_insert_slice(client->tag->stack, client->slice); // insert window to the tag frame_insert_window(lookup_frame(client->tag->frame, changes.tree_index->str), win); client_update_wm_hints(client); if (changes.focus) { // give focus to window if wanted // TODO: make this faster! // WARNING: this solution needs O(C + exp(D)) time where W is the count // of clients on this tag and D is the depth of the binary layout tree frame_focus_window(client->tag->frame, win); } HSAttribute attributes[] = { ATTRIBUTE_STRING( "winid", client->window_str, ATTR_READ_ONLY), ATTRIBUTE_STRING( "title", client->title, ATTR_READ_ONLY), ATTRIBUTE_BOOL( "fullscreen", client->fullscreen, client_attr_fullscreen), ATTRIBUTE_BOOL( "pseudotile", client->pseudotile, client_attr_pseudotile), ATTRIBUTE_BOOL( "ewmhrequests", client->ewmhrequests, ATTR_ACCEPT_ALL), ATTRIBUTE_BOOL( "ewmhnotify", client->ewmhnotify, ATTR_ACCEPT_ALL), ATTRIBUTE_BOOL( "sizehints", client->sizehints, ATTR_ACCEPT_ALL), ATTRIBUTE_BOOL( "urgent", client->urgent, client_attr_urgent), ATTRIBUTE_LAST, }; hsobject_set_attributes(&client->object, attributes); ewmh_window_update_tag(client->window, client->tag); tag_set_flags_dirty(); client_set_fullscreen(client, changes.fullscreen); ewmh_update_window_state(client); // add client after setting the correct tag for the new client // this ensures a panel can read the tag property correctly at this point ewmh_add_client(client->window); HSMonitor* monitor = find_monitor_with_tag(client->tag); if (monitor) { if (monitor != get_current_monitor() && changes.focus && changes.switchtag) { monitor_set_tag(get_current_monitor(), client->tag); } // TODO: monitor_apply_layout() maybe is called twice here if it // already is called by monitor_set_tag() monitor_apply_layout(monitor); } else { if (changes.focus && changes.switchtag) { monitor_set_tag(get_current_monitor(), client->tag); } } client_changes_free_members(&changes); grab_client_buttons(client, false); return client; }