Ejemplo n.º 1
0
/**
@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;
}
Ejemplo n.º 2
0
/**
@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);

}
Ejemplo n.º 3
0
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;
}