]> git.sur5r.net Git - i3/i3/commitdiff
Merge branch 'master' into next
authorMichael Stapelberg <michael@stapelberg.de>
Sat, 10 Nov 2012 08:01:24 +0000 (09:01 +0100)
committerMichael Stapelberg <michael@stapelberg.de>
Sat, 10 Nov 2012 08:01:24 +0000 (09:01 +0100)
1  2 
src/workspace.c
testcases/t/176-workspace-baf.t

diff --combined src/workspace.c
index 872ec768d99ad64038d35df85031db72bf463145,1e7071875cd97f186986723f193d2c6e9bba6fa6..ed00c9a7c89f12ef54e00be8f3b4240ccaee6cdb
@@@ -312,30 -312,12 +312,30 @@@ static void workspace_reassign_sticky(C
          workspace_reassign_sticky(current);
  }
  
 +/*
 + * Callback to reset the urgent flag of the given con to false. May be started by
 + * _workspace_show to avoid urgency hints being lost by switching to a workspace
 + * focusing the con.
 + *
 + */
 +static void workspace_defer_update_urgent_hint_cb(EV_P_ ev_timer *w, int revents) {
 +    Con *con = w->data;
 +
 +    DLOG("Resetting urgency flag of con %p by timer\n", con);
 +    con->urgent = false;
 +    con_update_parents_urgency(con);
 +    workspace_update_urgent_flag(con_get_workspace(con));
 +    tree_render();
 +
 +    ev_timer_stop(main_loop, con->urgency_timer);
 +    FREE(con->urgency_timer);
 +}
  
  static void _workspace_show(Con *workspace) {
      Con *current, *old = NULL;
  
      /* safe-guard against showing i3-internal workspaces like __i3_scratch */
 -    if (workspace->name[0] == '_' && workspace->name[1] == '_')
 +    if (con_is_internal(workspace))
          return;
  
      /* disable fullscreen for the other workspaces and get the workspace we are
      /* Remember currently focused workspace for switching back to it later with
       * the 'workspace back_and_forth' command.
       * NOTE: We have to duplicate the name as the original will be freed when
-      * the corresponding workspace is cleaned up. */
-     FREE(previous_workspace_name);
-     if (current)
-         previous_workspace_name = sstrdup(current->name);
+      * the corresponding workspace is cleaned up.
+      * NOTE: Internal cons such as __i3_scratch (when a scratchpad window is
+      * focused) are skipped, see bug #868. */
+     if (current && !con_is_internal(current)) {
+         FREE(previous_workspace_name);
+         if (current) {
+             previous_workspace_name = sstrdup(current->name);
+             DLOG("Setting previous_workspace_name = %s\n", previous_workspace_name);
+         }
+     }
  
      workspace_reassign_sticky(workspace);
  
 -    LOG("switching to %p\n", workspace);
 +    DLOG("switching to %p / %s\n", workspace, workspace->name);
      Con *next = con_descend_focused(workspace);
  
 +    /* Memorize current output */
 +    Con *old_output = con_get_output(focused);
 +
 +    /* Display urgency hint for a while if the newly visible workspace would
 +     * focus and thereby immediately destroy it */
 +    if (next->urgent && (int)(config.workspace_urgency_timer * 1000) > 0) {
 +        /* focus for now… */
 +        con_focus(next);
 +
 +        /* … but immediately reset urgency flags; they will be set to false by
 +         * the timer callback in case the container is focused at the time of
 +         * its expiration */
 +        focused->urgent = true;
 +        workspace->urgent = true;
 +
 +        if (focused->urgency_timer == NULL) {
 +            DLOG("Deferring reset of urgency flag of con %p on newly shown workspace %p\n",
 +                    focused, workspace);
 +            focused->urgency_timer = scalloc(sizeof(struct ev_timer));
 +            /* use a repeating timer to allow for easy resets */
 +            ev_timer_init(focused->urgency_timer, workspace_defer_update_urgent_hint_cb,
 +                    config.workspace_urgency_timer, config.workspace_urgency_timer);
 +            focused->urgency_timer->data = focused;
 +            ev_timer_start(main_loop, focused->urgency_timer);
 +        } else {
 +            DLOG("Resetting urgency timer of con %p on workspace %p\n",
 +                    focused, workspace);
 +            ev_timer_again(main_loop, focused->urgency_timer);
 +        }
 +    } else
 +        con_focus(next);
 +
 +    DLOG("old = %p / %s\n", old, (old ? old->name : "(null)"));
 +    /* Close old workspace if necessary. This must be done *after* doing
 +     * urgency handling, because tree_close() will do a con_focus() on the next
 +     * client, which will clear the urgency flag too early. Also, there is no
 +     * way for con_focus() to know about when to clear urgency immediately and
 +     * when to defer it. */
      if (old && TAILQ_EMPTY(&(old->nodes_head)) && TAILQ_EMPTY(&(old->floating_head))) {
          /* check if this workspace is currently visible */
          if (!workspace_is_visible(old)) {
          }
      }
  
 -    /* Memorize current output */
 -    Con *old_output = con_get_output(focused);
 -
 -    con_focus(next);
      workspace->fullscreen_mode = CF_OUTPUT;
      LOG("focused now = %p / %s\n", focused, focused->name);
  
@@@ -445,7 -398,8 +450,7 @@@ void workspace_show(Con *workspace) 
   */
  void workspace_show_by_name(const char *num) {
      Con *workspace;
 -    bool changed_num_workspaces;
 -    workspace = workspace_get(num, &changed_num_workspaces);
 +    workspace = workspace_get(num, NULL);
      _workspace_show(workspace);
  }
  
@@@ -465,7 -419,7 +470,7 @@@ Con* workspace_next(void) 
          /* If currently a numbered workspace, find next numbered workspace. */
          TAILQ_FOREACH(output, &(croot->nodes_head), nodes) {
              /* Skip outputs starting with __, they are internal. */
 -            if (output->name[0] == '_' && output->name[1] == '_')
 +            if (con_is_internal(output))
                  continue;
              NODES_FOREACH(output_get_content(output)) {
                  if (child->type != CT_WORKSPACE)
          bool found_current = false;
          TAILQ_FOREACH(output, &(croot->nodes_head), nodes) {
              /* Skip outputs starting with __, they are internal. */
 -            if (output->name[0] == '_' && output->name[1] == '_')
 +            if (con_is_internal(output))
                  continue;
              NODES_FOREACH(output_get_content(output)) {
                  if (child->type != CT_WORKSPACE)
      if (!next) {
          TAILQ_FOREACH(output, &(croot->nodes_head), nodes) {
              /* Skip outputs starting with __, they are internal. */
 -            if (output->name[0] == '_' && output->name[1] == '_')
 +            if (con_is_internal(output))
                  continue;
              NODES_FOREACH(output_get_content(output)) {
                  if (child->type != CT_WORKSPACE)
@@@ -537,7 -491,7 +542,7 @@@ Con* workspace_prev(void) 
          /* If numbered workspace, find previous numbered workspace. */
          TAILQ_FOREACH_REVERSE(output, &(croot->nodes_head), nodes_head, nodes) {
              /* Skip outputs starting with __, they are internal. */
 -            if (output->name[0] == '_' && output->name[1] == '_')
 +            if (con_is_internal(output))
                  continue;
              NODES_FOREACH_REVERSE(output_get_content(output)) {
                  if (child->type != CT_WORKSPACE || child->num == -1)
          bool found_current = false;
          TAILQ_FOREACH_REVERSE(output, &(croot->nodes_head), nodes_head, nodes) {
              /* Skip outputs starting with __, they are internal. */
 -            if (output->name[0] == '_' && output->name[1] == '_')
 +            if (con_is_internal(output))
                  continue;
              NODES_FOREACH_REVERSE(output_get_content(output)) {
                  if (child->type != CT_WORKSPACE)
      if (!prev) {
          TAILQ_FOREACH_REVERSE(output, &(croot->nodes_head), nodes_head, nodes) {
              /* Skip outputs starting with __, they are internal. */
 -            if (output->name[0] == '_' && output->name[1] == '_')
 +            if (con_is_internal(output))
                  continue;
              NODES_FOREACH_REVERSE(output_get_content(output)) {
                  if (child->type != CT_WORKSPACE)
@@@ -716,22 -670,6 +721,22 @@@ void workspace_back_and_forth(void) 
      workspace_show_by_name(previous_workspace_name);
  }
  
 +/*
 + * Returns the previously focused workspace con, or NULL if unavailable.
 + *
 + */
 +Con *workspace_back_and_forth_get(void) {
 +    if (!previous_workspace_name) {
 +        DLOG("no previous workspace name set.");
 +        return NULL;
 +    }
 +
 +    Con *workspace;
 +    workspace = workspace_get(previous_workspace_name, NULL);
 +
 +    return workspace;
 +}
 +
  static bool get_urgency_flag(Con *con) {
      Con *child;
      TAILQ_FOREACH(child, &(con->nodes_head), nodes)
@@@ -768,6 -706,7 +773,6 @@@ void ws_force_orientation(Con *ws, orie
      /* 1: create a new split container */
      Con *split = con_new(NULL, NULL);
      split->parent = ws;
 -    split->split = true;
  
      /* 2: copy layout from workspace */
      split->layout = ws->layout;
@@@ -819,6 -758,7 +824,6 @@@ Con *workspace_attach_to(Con *ws) 
      /* 1: create a new split container */
      Con *new = con_new(NULL, NULL);
      new->parent = ws;
 -    new->split = true;
  
      /* 2: set the requested layout on the split con */
      new->layout = ws->workspace_layout;
  
      return new;
  }
 +
 +/**
 + * Creates a new container and re-parents all of children from the given
 + * workspace into it.
 + *
 + * The container inherits the layout from the workspace.
 + */
 +Con *workspace_encapsulate(Con *ws) {
 +    if (TAILQ_EMPTY(&(ws->nodes_head))) {
 +        ELOG("Workspace %p / %s has no children to encapsulate\n", ws, ws->name);
 +        return NULL;
 +    }
 +
 +    Con *new = con_new(NULL, NULL);
 +    new->parent = ws;
 +    new->layout = ws->layout;
 +
 +    DLOG("Moving children of workspace %p / %s into container %p\n",
 +        ws, ws->name, new);
 +
 +    Con *child;
 +    while (!TAILQ_EMPTY(&(ws->nodes_head))) {
 +        child = TAILQ_FIRST(&(ws->nodes_head));
 +        con_detach(child);
 +        con_attach(child, new, true);
 +    }
 +
 +    con_attach(new, ws, true);
 +
 +    return new;
 +}
index 8ed33030818343e595db4cfcf9df558ad79b60b8,659d469d1a31e062dc5fbe81b5bd4117b221fb91..bad76ec8987938476bde92f25071a4e78a3e9dce
@@@ -47,33 -47,6 +47,33 @@@ ok(get_ws($second_ws)->{focused}, 'seco
  cmd qq|workspace "$second_ws"|;
  ok(get_ws($second_ws)->{focused}, 'second workspace still focused');
  
 +################################################################################
 +# verify that 'move workspace back_and_forth' works as expected
 +################################################################################
 +
 +cmd qq|workspace "$first_ws"|;
 +my $first_win = open_window;
 +
 +cmd qq|workspace "$second_ws"|;
 +my $second_win = open_window;
 +
 +is(@{get_ws_content($first_ws)}, 1, 'one container on ws 1 before moving');
 +cmd 'move workspace back_and_forth';
 +is(@{get_ws_content($first_ws)}, 2, 'two containers on ws 1 before moving');
 +
 +my $third_win = open_window;
 +
 +################################################################################
 +# verify that moving to the current ws is a no-op without
 +# workspace_auto_back_and_forth.
 +################################################################################
 +
 +cmd qq|workspace "$first_ws"|;
 +
 +is(@{get_ws_content($second_ws)}, 1, 'one container on ws 2 before moving');
 +cmd qq|move workspace "$first_ws"|;
 +is(@{get_ws_content($second_ws)}, 1, 'still one container');
 +
  exit_gracefully($pid);
  
  #####################################################################
@@@ -99,19 -72,6 +99,19 @@@ ok(get_ws($third_ws)->{focused}, 'thir
  
  cmd qq|workspace "$third_ws"|;
  ok(get_ws($second_ws)->{focused}, 'second workspace focused');
 +$first_win = open_window;
 +
 +################################################################################
 +# verify that moving to the current ws moves to the previous one with
 +# workspace_auto_back_and_forth.
 +################################################################################
 +
 +cmd qq|workspace "$first_ws"|;
 +$second_win = open_window;
 +
 +is(@{get_ws_content($second_ws)}, 1, 'one container on ws 2 before moving');
 +cmd qq|move workspace "$first_ws"|;
 +is(@{get_ws_content($second_ws)}, 2, 'two containers on ws 2');
  
  ################################################################################
  # Now see if "workspace number <number>" also works as expected with
@@@ -146,6 -106,23 +146,23 @@@ is(focused_ws, '6: baz', 'workspace 6 n
  cmd 'workspace number 6';
  is(focused_ws, '5: foo', 'workspace 5 focused again');
  
+ ################################################################################
+ # Place a window in the scratchpad, see if BAF works after showing the
+ # scratchpad window.
+ ################################################################################
+ my $scratchwin = open_window;
+ cmd 'move scratchpad';
+ # show scratchpad window
+ cmd 'scratchpad show';
+ # hide scratchpad window
+ cmd 'scratchpad show';
+ cmd 'workspace back_and_forth';
+ is(focused_ws, '6: baz', 'workspace 6 now focused');
  exit_gracefully($pid);
  
  done_testing;