]> git.sur5r.net Git - i3/i3/commitdiff
Merge pull request #3475 from Gravemind/fix-i3bar-re-hidden-on-any-modifier
authorOrestis <orestisf1993@gmail.com>
Tue, 23 Oct 2018 15:41:11 +0000 (18:41 +0300)
committerGitHub <noreply@github.com>
Tue, 23 Oct 2018 15:41:11 +0000 (18:41 +0300)
i3bar: Fix i3bar re-hidden by any modifier (#3474)

1  2 
i3bar/src/xcb.c

diff --combined i3bar/src/xcb.c
index d43a4bdd5373b53d1d16bb9dee8cdf0ae6afd945,39368c88bdd673546572d875e9866a1fad288628..c0486181b02933db87200396c318e0ee322924e2
@@@ -92,9 -92,6 +92,9 @@@ static mode binding
  /* Indicates whether a new binding mode was recently activated */
  bool activated_mode = false;
  
 +/* The output in which the tray should be displayed. */
 +static i3_output *output_for_tray;
 +
  /* The parsed colors */
  struct xcb_colors_t {
      color_t bar_fg;
@@@ -149,13 -146,13 +149,13 @@@ int _xcb_request_failed(xcb_void_cookie
      return 0;
  }
  
 -uint32_t get_sep_offset(struct status_block *block) {
 +static uint32_t get_sep_offset(struct status_block *block) {
      if (!block->no_separator && block->sep_block_width > 0)
          return block->sep_block_width / 2 + block->sep_block_width % 2;
      return 0;
  }
  
 -int get_tray_width(struct tc_head *trayclients) {
 +static int get_tray_width(struct tc_head *trayclients) {
      trayclient *trayclient;
      int tray_width = 0;
      TAILQ_FOREACH_REVERSE(trayclient, trayclients, tc_head, tailq) {
@@@ -196,7 -193,7 +196,7 @@@ static void draw_separator(i3_output *o
      }
  }
  
 -uint32_t predict_statusline_length(bool use_short_text) {
 +static uint32_t predict_statusline_length(bool use_short_text) {
      uint32_t width = 0;
      struct status_block *block;
  
  /*
   * Redraws the statusline to the output's statusline_buffer
   */
 -void draw_statusline(i3_output *output, uint32_t clip_left, bool use_focus_colors, bool use_short_text) {
 +static void draw_statusline(i3_output *output, uint32_t clip_left, bool use_focus_colors, bool use_short_text) {
      struct status_block *block;
  
      color_t bar_color = (use_focus_colors ? colors.focus_bar_bg : colors.bar_bg);
   * Hides all bars (unmaps them)
   *
   */
 -void hide_bars(void) {
 +static void hide_bars(void) {
      if ((config.hide_on_modifier == M_DOCK) || (config.hidden_state == S_SHOW && config.hide_on_modifier == M_HIDE)) {
          return;
      }
   * Unhides all bars (maps them)
   *
   */
 -void unhide_bars(void) {
 +static void unhide_bars(void) {
      if (config.hide_on_modifier != M_HIDE) {
          return;
      }
@@@ -460,7 -457,7 +460,7 @@@ static bool execute_custom_command(xcb_
   * wheel was used and change the workspace appropriately
   *
   */
 -void handle_button(xcb_button_press_event_t *event) {
 +static void handle_button(xcb_button_press_event_t *event) {
      /* Determine, which bar was clicked */
      i3_output *walk;
      xcb_window_t bar = event->event;
@@@ -761,16 -758,58 +761,16 @@@ static void handle_client_message(xcb_c
              }
  
              DLOG("X window %08x requested docking\n", client);
 -            i3_output *output = NULL;
 -            i3_output *walk = NULL;
 -            tray_output_t *tray_output = NULL;
 -            /* We need to iterate through the tray_output assignments first in
 -             * order to prioritize them. Otherwise, if this bar manages two
 -             * outputs and both are assigned as tray_output as well, the first
 -             * output in our list would receive the tray rather than the first
 -             * one defined via tray_output. */
 -            TAILQ_FOREACH(tray_output, &(config.tray_outputs), tray_outputs) {
 -                SLIST_FOREACH(walk, outputs, slist) {
 -                    if (!walk->active)
 -                        continue;
 -
 -                    if (strcasecmp(walk->name, tray_output->output) == 0) {
 -                        DLOG("Found tray_output assignment for output %s.\n", walk->name);
 -                        output = walk;
 -                        break;
 -                    }
  
 -                    if (walk->primary && strcasecmp("primary", tray_output->output) == 0) {
 -                        DLOG("Found tray_output assignment on primary output %s.\n", walk->name);
 -                        output = walk;
 -                        break;
 -                    }
 -                }
 -
 -                /* If we found an output, we're done. */
 -                if (output != NULL)
 -                    break;
 -            }
 -
 -            /* If no tray_output has been specified, we fall back to the first
 -             * available output. */
 -            if (output == NULL && TAILQ_EMPTY(&(config.tray_outputs))) {
 -                SLIST_FOREACH(walk, outputs, slist) {
 -                    if (!walk->active)
 -                        continue;
 -                    DLOG("Falling back to output %s because no primary output is configured\n", walk->name);
 -                    output = walk;
 -                    break;
 -                }
 -            }
 -
 -            if (output == NULL) {
 -                ELOG("No output found\n");
 +            if (output_for_tray == NULL) {
 +                ELOG("No output found for tray\n");
                  return;
              }
  
              xcb_void_cookie_t rcookie = xcb_reparent_window(xcb_connection,
                                                              client,
 -                                                            output->bar.id,
 -                                                            output->rect.w - icon_size - logical_px(config.tray_padding),
 +                                                            output_for_tray->bar.id,
 +                                                            output_for_tray->rect.w - icon_size - logical_px(config.tray_padding),
                                                              logical_px(config.tray_padding));
              if (xcb_request_failed(rcookie, "Could not reparent window. Maybe it is using an incorrect depth/visual?"))
                  return;
              ev->format = 32;
              ev->data.data32[0] = XCB_CURRENT_TIME;
              ev->data.data32[1] = XEMBED_EMBEDDED_NOTIFY;
 -            ev->data.data32[2] = output->bar.id;
 +            ev->data.data32[2] = output_for_tray->bar.id;
              ev->data.data32[3] = xe_version;
              xcb_send_event(xcb_connection,
                             0,
              tc->win = client;
              tc->xe_version = xe_version;
              tc->mapped = false;
 -            TAILQ_INSERT_TAIL(output->trayclients, tc, tailq);
 +            TAILQ_INSERT_TAIL(output_for_tray->trayclients, tc, tailq);
  
              if (map_it) {
                  DLOG("Mapping dock client\n");
@@@ -1041,7 -1080,7 +1041,7 @@@ static void handle_resize_request(xcb_r
   * events from X11, handle them, then flush our outgoing queue.
   *
   */
 -void xcb_prep_cb(struct ev_loop *loop, ev_prepare *watcher, int revents) {
 +static void xcb_prep_cb(struct ev_loop *loop, ev_prepare *watcher, int revents) {
      xcb_generic_event_t *event;
  
      if (xcb_connection_has_error(xcb_connection)) {
  
              xcb_xkb_state_notify_event_t *state = (xcb_xkb_state_notify_event_t *)event;
              const uint32_t mod = (config.modifier & 0xFFFF);
-             mod_pressed = (mod != 0 && (state->mods & mod) == mod);
-             if (state->xkbType == XCB_XKB_STATE_NOTIFY && config.modifier != XCB_NONE) {
-                 if (mod_pressed) {
-                     activated_mode = false;
-                     unhide_bars();
-                 } else if (!activated_mode) {
-                     hide_bars();
+             const bool new_mod_pressed = (mod != 0 && (state->mods & mod) == mod);
+             if (new_mod_pressed != mod_pressed) {
+                 mod_pressed = new_mod_pressed;
+                 if (state->xkbType == XCB_XKB_STATE_NOTIFY && config.modifier != XCB_NONE) {
+                     if (mod_pressed) {
+                         activated_mode = false;
+                         unhide_bars();
+                     } else if (!activated_mode) {
+                         hide_bars();
+                     }
                  }
              }
  
   * are triggered
   *
   */
 -void xcb_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) {
 +static void xcb_io_cb(struct ev_loop *loop, ev_io *watcher, int revents) {
  }
  
  /*
   * depend on 'config'.
   *
   */
 -char *init_xcb_early() {
 +char *init_xcb_early(void) {
      /* FIXME: xcb_connect leaks memory */
      xcb_connection = xcb_connect(NULL, &screen);
      if (xcb_connection_has_error(xcb_connection)) {
   * in xcb.
   *
   */
 -void register_xkb_keyevents() {
 +static void register_xkb_keyevents(void) {
      const xcb_query_extension_reply_t *extreply;
      extreply = xcb_get_extension_data(conn, &xcb_xkb_id);
      if (!extreply->present) {
   * Deregister from xkb keyevents.
   *
   */
 -void deregister_xkb_keyevents() {
 +static void deregister_xkb_keyevents(void) {
      xcb_xkb_select_events(conn,
                            XCB_XKB_ID_USE_CORE_KBD,
                            0,
@@@ -1299,7 -1341,7 +1302,7 @@@ static void send_tray_clientmessage(voi
   * atom. Afterwards, tray clients will send ClientMessages to our window.
   *
   */
 -void init_tray(void) {
 +static void init_tray(void) {
      DLOG("Initializing system tray functionality\n");
      /* request the tray manager atom for the X11 display we are running on */
      char atomname[strlen("_NET_SYSTEM_TRAY_S") + 11];
@@@ -1528,7 -1570,7 +1531,7 @@@ void destroy_window(i3_output *output) 
  
  /* Strut partial tells i3 where to reserve space for i3bar. This is determined
   * by the `position` bar config directive. */
 -xcb_void_cookie_t config_strut_partial(i3_output *output) {
 +static xcb_void_cookie_t config_strut_partial(i3_output *output) {
      /* A local struct to save the strut_partial property */
      struct {
          uint32_t left;
                                 &strut_partial);
  }
  
 +/*
 + * Returns the output which should hold the tray, if one exists.
 + *
 + * An output is returned in these scenarios:
 + *   1. A specific output was listed in tray_outputs which is also in the list
 + *   of outputs managed by this bar.
 + *   2. No tray_output directive was specified. In this case, we use the first
 + *   available output.
 + *   3. 'tray_output primary' was specified. In this case we use the primary
 + *   output.
 + *
 + * Three scenarios in which we specifically don't want to use a tray:
 + *   1. 'tray_output none' was specified.
 + *   2. A specific output was listed as a tray_output, but is not one of the
 + *   outputs managed by this bar. For example, consider tray_outputs == [VGA-1],
 + *   but outputs == [HDMI-1].
 + *   3. 'tray_output primary' was specified and no output in the list is
 + *   primary.
 + */
 +static i3_output *get_tray_output(void) {
 +    i3_output *output = NULL;
 +    if (TAILQ_EMPTY(&(config.tray_outputs))) {
 +        /* No tray_output specified, use first active output. */
 +        SLIST_FOREACH(output, outputs, slist) {
 +            if (output->active) {
 +                return output;
 +            }
 +        }
 +        return NULL;
 +    } else if (strcasecmp(TAILQ_FIRST(&(config.tray_outputs))->output, "none") == 0) {
 +        /* Check for "tray_output none" */
 +        return NULL;
 +    }
 +
 +    /* If one or more tray_output assignments were specified, we ensure that at
 +     * least one of them is actually an output managed by this instance. */
 +    tray_output_t *tray_output;
 +    TAILQ_FOREACH(tray_output, &(config.tray_outputs), tray_outputs) {
 +        SLIST_FOREACH(output, outputs, slist) {
 +            if (output->active &&
 +                (strcasecmp(output->name, tray_output->output) == 0 ||
 +                 (strcasecmp(tray_output->output, "primary") == 0 && output->primary))) {
 +                return output;
 +            }
 +        }
 +    }
 +
 +    return NULL;
 +}
 +
  /*
   * Reconfigure all bars and create new bars for recently activated outputs
   *
  void reconfig_windows(bool redraw_bars) {
      uint32_t mask;
      uint32_t values[6];
 -    static bool tray_configured = false;
  
      i3_output *walk;
      SLIST_FOREACH(walk, outputs, slist) {
                  exit(EXIT_FAILURE);
              }
  
 -            /* Unless "tray_output none" was specified, we need to initialize the tray. */
 -            bool no_tray = false;
 -            if (!(TAILQ_EMPTY(&(config.tray_outputs)))) {
 -                no_tray = strcasecmp(TAILQ_FIRST(&(config.tray_outputs))->output, "none") == 0;
 -            }
 -
 -            /*
 -             * There are three scenarios in which we need to initialize the tray:
 -             *   1. A specific output was listed in tray_outputs which is also
 -             *      in the list of outputs managed by this bar.
 -             *   2. No tray_output directive was specified. In this case, we
 -             *      use the first available output.
 -             *   3. 'tray_output primary' was specified. In this case we use the
 -             *      primary output.
 -             *
 -             * Three scenarios in which we specifically don't want to
 -             * initialize the tray are:
 -             *   1. 'tray_output none' was specified.
 -             *   2. A specific output was listed as a tray_output, but is not
 -             *      one of the outputs managed by this bar. For example, consider
 -             *      tray_outputs == [VGA-1], but outputs == [HDMI-1].
 -             *   3. 'tray_output primary' was specified and no output in the list
 -             *      is primary.
 -             */
 -            if (!tray_configured && !no_tray) {
 -                /* If no tray_output was specified, we go ahead and initialize the tray as
 -                 * we will be using the first available output. */
 -                if (TAILQ_EMPTY(&(config.tray_outputs))) {
 -                    init_tray();
 -                }
 -
 -                /* If one or more tray_output assignments were specified, we ensure that at least one of
 -                 * them is actually an output managed by this instance. */
 -                tray_output_t *tray_output;
 -                TAILQ_FOREACH(tray_output, &(config.tray_outputs), tray_outputs) {
 -                    i3_output *output;
 -                    bool found = false;
 -                    SLIST_FOREACH(output, outputs, slist) {
 -                        if (strcasecmp(output->name, tray_output->output) == 0 ||
 -                            (strcasecmp(tray_output->output, "primary") == 0 && output->primary)) {
 -                            found = true;
 -                            init_tray();
 -                            break;
 -                        }
 -                    }
 -
 -                    if (found)
 -                        break;
 -                }
 -
 -                tray_configured = true;
 -            }
          } else {
              /* We already have a bar, so we just reconfigure it */
              mask = XCB_CONFIG_WINDOW_X |
              }
          }
      }
 +
 +    /* Finally, check if we want to initialize the tray or destroy the selection
 +     * window. The result of get_tray_output() is cached. */
 +    output_for_tray = get_tray_output();
 +    if (output_for_tray) {
 +        if (selwin == XCB_NONE) {
 +            init_tray();
 +        }
 +    } else if (selwin != XCB_NONE) {
 +        DLOG("Destroying tray selection window\n");
 +        xcb_destroy_window(xcb_connection, selwin);
 +        selwin = XCB_NONE;
 +    }
  }
  
  /*