/** @brief Adds a frame to a workspace, creating the workspace if required. Indirectly creates workspaces and frames. Gets the program name from the frame using the class hints (load_program_name). If the program name doesn't match the name of any workspace, creates a new workspace. If the workspace is new, switch to the workspace. Try and tile the frame if its mode is tiling. Decide whether to show the frame and whether to focus it. @return the index of the workspace the frame was inserted into or -1 if an error occurred. **/ int add_frame_to_workspace(Display *display, struct Workspace_list *workspaces, Window framed_window, int *current_workspace, struct Workspace **frames , struct Popup_menu *window_menu , struct Separators *seps , const struct Workarea *workarea , struct Themes *themes, struct Cursors *cursors, struct Atoms *atoms) { int home_w; //index of the home workspace of the frame int true_frame_index; //index of the frame in the global frame list in workspaces Bool new_workspace = False; //boolean indicator to check if a workspace was just created. char *program_name = load_program_name(display, framed_window); if(program_name == NULL) { #ifdef SHOW_MAP_REQUEST_EVENT printf("Warning, could not load program name for window %lu. ", framed_window); printf("Creating default workspace\n"); #endif make_default_program_name(display, framed_window, "Other Programs"); program_name = load_program_name(display, framed_window); } if(program_name == NULL) {perror("Error: out of memory"); return -1;} //probably out of memory for(home_w = 0; home_w < workspaces->used_workspaces; home_w++) { if(strcmp(program_name, workspaces->list[home_w].workspace_name) == 0) { XFree(program_name); break; } } if(home_w == workspaces->used_workspaces) { //create_statup workspaces only creates a workspace if there is at least one home_w = create_workspace(display, workspaces, program_name, themes); if(home_w < 0) { perror("Error: could not create new workspace\n"); return -1; } new_workspace = True; } if(ensure_empty_frame_slots(workspaces) == False) return -1; if(ensure_empty_frame_reference_slots(&workspaces->list[home_w]) == False) return -1; true_frame_index = workspaces->used_frames; if(!create_frame(display, &workspaces->frame_list[true_frame_index], framed_window, window_menu, seps, workarea, themes, cursors, atoms)) { //if the window wasn't created, and the workspace is now empty, remove the workspace if(new_workspace) { remove_workspace(display, workspaces, home_w); } return -1; } workspaces->used_frames++; #ifdef SHOW_MAP_REQUEST_EVENT printf("Workspace %d, real frame index %d, frame_name %s, window %lu, workspace_name %s\n", home_w, true_frame_index , workspaces->frame_list[true_frame_index].window_name, framed_window, workspaces->list[home_w].workspace_name); #endif check_and_set_new_frame_focus (display, &workspaces->frame_list[true_frame_index], &workspaces->list[home_w]); //check if it's neutral Bool show_in_other_workspaces = suitable_for_foreign_workspaces(&workspaces->frame_list[true_frame_index]); enum Window_state original_state = workspaces->frame_list[true_frame_index].state; //in case it is fullscreen { //save state of window in home workspace and other workspaces if it's meant to be shown in other workspaces. //Otherwise the saved state entry will simply zero'd. int workspace_index = 0; do { if(!show_in_other_workspaces) workspace_index = home_w; //only do one pass if we don't want to make it available workspaces->list[workspace_index].states[true_frame_index].need_to_tile = 0; //reset if(workspace_index == home_w) { workspaces->list[workspace_index].states[true_frame_index].available = 1; if(workspaces->frame_list[true_frame_index].mode == tiling && home_w != *current_workspace) { workspaces->list[workspace_index].states[true_frame_index].need_to_tile = 1; } change_frame_state(display, &workspaces->frame_list[true_frame_index], original_state, seps, workarea, themes, atoms); save_frame_state(&workspaces->list[workspace_index].states[true_frame_index], &workspaces->frame_list[true_frame_index]); } else if (show_in_other_workspaces) { workspaces->list[workspace_index].states[true_frame_index].available = 2; change_frame_state(display, &workspaces->frame_list[true_frame_index], minimized, seps, workarea, themes, atoms); save_frame_state(&workspaces->list[workspace_index].states[true_frame_index], &workspaces->frame_list[true_frame_index]); } workspace_index++; } while(show_in_other_workspaces && workspace_index < workspaces->used_workspaces); } if(home_w == *current_workspace && *current_workspace != -1) { //new window is in the current workspace //save the reference struct Workspace *workspace = &workspaces->list[*current_workspace]; int frame_ref_index = workspace->used; workspace->list[frame_ref_index] = &workspaces->frame_list[true_frame_index]; workspace->used++; change_frame_state(display, &workspaces->frame_list[true_frame_index], original_state, seps, workarea, themes, atoms); if(workspace->list[frame_ref_index]->mode == tiling && workspace->list[frame_ref_index]->state != fullscreen) { if(!redrop_frame(display, workspace, frame_ref_index, workarea, themes)) { change_frame_state(display, workspace->list[frame_ref_index], minimized, seps, workarea, themes, atoms); } } #ifdef SHOW_MAP_REQUEST_EVENT printf("Created and mapped window in workspace %d\n", *current_workspace); #endif if(workspaces->frame_list[true_frame_index].state != minimized) XMapWindow(display, workspace->list[frame_ref_index]->widgets[frame_parent].widget); XMapWindow(display, workspace->list[frame_ref_index]->menu.item); if(workspace->list[frame_ref_index]->focussed) { recover_focus(display, &workspaces->list[*current_workspace], atoms); } update_client_list(display, &workspaces->list[*current_workspace], atoms); } if(home_w != *current_workspace) { change_to_workspace(display, workspaces, current_workspace, frames, home_w, seps, workarea, themes, atoms); } XFlush(display); return home_w; }
/** @pre all parameters intitalized and allocated properly. @brief This function changes the user's workspace to the workspace at the specified index. If a negative index is passed (This is done when the currently open workspace is removed), it changes to a default workspace which is currently 0. If a negative index is passed but no workspace is open nothing happens. Generally, it is expected that at least one workspace is open. Windows from other workspaces are unmapped. @post The user's workspace has visibly changed. @return void **/ void change_to_workspace(Display *display, struct Workspace_list *workspaces, int *current_workspace, struct Workspace **frames, int index, struct Separators *seps, const struct Workarea *workarea, struct Themes *themes, struct Atoms *atoms) { struct Workspace *workspace = &workspaces->list[*current_workspace]; if(*current_workspace != -1) *frames = workspace; struct Saved_frame_state *frame_state; if(workspaces->used_workspaces == 0) { *frames = NULL; *current_workspace = -1; return; //don't do anything if no windows are open } if(*current_workspace < workspaces->used_workspaces /*this function is sometimes called to change from an invalid workspace that has been closed */ && *current_workspace >= 0) { for(int i = 0; i < workspace->used; i++) { //So we can figure out where to save the frame state we need to calculate the pointer offset. int real_frame_index = get_offset_in_array(workspace->list[i], workspaces->frame_list, sizeof(struct Frame)); if(workspace->list[i]->sticky == False) { XUnmapWindow(display, workspace->list[i]->widgets[frame_parent].widget); XUnmapWindow(display, workspace->list[i]->menu.item); } //printf("real_frame_index %d, i = %d, current_workspace %d\n", real_frame_index, i, *current_workspace); frame_state = &workspace->states[real_frame_index]; frame_state->need_to_tile = 0; save_frame_state(frame_state, workspace->list[i]); } free(workspace->list); workspace->list = NULL; workspace->used = 0; } XSync(display, False); //if index is -1, change to default workspace which is 0 if(index < 0 && workspaces->used_workspaces > 0) index = 0; *current_workspace = index; workspace = &workspaces->list[*current_workspace]; *frames = workspace; workspace->max = DEFAULT_STARTING_FRAMES; workspace->list = malloc(sizeof(struct Frames *) * workspace->max ); if(!workspace->list) { perror("Couldn't allocate frame list"); return; } //Do all the panels because we want them to be tiled first. for(int i = 0; i < workspaces->used_frames; i++) { if(workspaces->frame_list[i].sticky == True) { if(ensure_empty_frame_reference_slots(workspace) == False) { perror("Couldn't allocate frame list"); return; } int ref_index = workspace->used; struct Frame *frame = workspace->list[ref_index] = &workspaces->frame_list[i]; if(drop_frame(workspace, ref_index, False, workarea)) { //this should be easy as they should already be non-overlapping change_frame_mode(display, frame, tiling, workarea, themes); } else { change_frame_state(display, frame, minimized, seps, workarea, themes, atoms); fprintf(stderr, "Couldn't tile panel! It is called %s\n", frame->window_name); } resize_frame(display, frame, workarea, themes); stack_frame(display, frame, seps); XMapWindow(display, frame->widgets[frame_parent].widget); //Actually only needs to be mapped the first time but doesn't matter workspace->used++; } } for(int i = 0; i < workspaces->used_frames; i++) { frame_state = &workspace->states[i]; if(frame_state->available != 0 && frame_state->sticky == False) { if(ensure_empty_frame_reference_slots(workspace) == False) { perror("Couldn't allocate frame list"); return; } int ref_index = workspace->used; struct Frame *frame = workspace->list[ref_index] = &workspaces->frame_list[i]; load_frame_state(display, frame_state, frame, seps, workarea, themes, atoms); if(workspace->states[i].need_to_tile) { if(drop_frame(workspace, ref_index, False, workarea)) { //this should be easy as they should already be non-overlapping change_frame_mode(display, frame, tiling, workarea, themes); } else { change_frame_state(display, frame, minimized, seps, workarea, themes, atoms); //TODO set urgency hint } workspace->states[i].need_to_tile = 0; } else if(frame->mode == floating) { if(!drop_frame(workspace, ref_index, True, workarea)) { change_frame_state(display, frame, minimized, seps, workarea, themes, atoms); //TODO set urgency hint } } resize_frame(display, frame, workarea, themes); stack_frame(display, frame, seps); if(frame->state != minimized) XMapWindow(display, frame->widgets[frame_parent].widget); XMapWindow(display, workspace->list[ref_index]->menu.item); workspace->used++; } } update_client_list(display, workspace, atoms); // printf("changing focus to one in new workspace\n"); recover_focus(display, workspace, atoms); XFlush(display); }
void lgssd_run() { int ret; struct sigaction dn_act; int fd; time_t child_check = 0; pid_t child_pid; /* Taken from linux/Documentation/dnotify.txt: */ dn_act.sa_sigaction = dir_notify_handler; sigemptyset(&dn_act.sa_mask); dn_act.sa_flags = SA_SIGINFO; sigaction(DNOTIFY_SIGNAL, &dn_act, NULL); if ((fd = open(pipefs_dir, O_RDONLY)) == -1) { printerr(0, "ERROR: failed to open %s: %s\n", pipefs_dir, strerror(errno)); return; } fcntl(fd, F_SETSIG, DNOTIFY_SIGNAL); fcntl(fd, F_NOTIFY, DN_CREATE|DN_DELETE|DN_MODIFY|DN_MULTISHOT); init_client_list(); while (1) { while (dir_changed) { dir_changed = 0; printerr(2, "pipefs root dir changed\n"); if (update_client_list()) { printerr(0, "ERROR: couldn't update " "client list\n"); goto out; } } /* every 5s cleanup possible zombies of child processes */ if (time(NULL) - child_check >= 5) { printerr(3, "check zombie children...\n"); while (1) { child_pid = waitpid(-1, NULL, WNOHANG); if (child_pid <= 0) break; printerr(2, "terminate zombie child: %d\n", child_pid); } child_check = time(NULL); } /* race condition here: dir_changed could be set before we * enter the poll, and we'd never notice if it weren't for the * timeout. */ ret = poll(pollarray, pollsize, POLL_MILLISECS); if (ret < 0) { if (errno != EINTR) printerr(0, "WARNING: error return from poll\n"); } else if (ret == 0) { /* timeout */ } else { /* ret > 0 */ scan_poll_results(ret); } } out: close(fd); return; }