]> git.sur5r.net Git - i3/i3/commitdiff
Close & reopen tray selwin when needed 3451/head
authorOrestis Floros <orestisf1993@gmail.com>
Thu, 11 Oct 2018 20:19:21 +0000 (23:19 +0300)
committerOrestis Floros <orestisf1993@gmail.com>
Tue, 23 Oct 2018 13:41:09 +0000 (16:41 +0300)
Fixes #1329
Fixes #3317 (duplicate)
Examples where the tray "disappeared":
- Start without a "tray_output", reload config with "tray_output none",
remove "tray_output none" and reload.
- Start with "tray_output primary" (or "tray_output <output>"), disable
the primary output and then reconnect it.

Fixes #2010
Cached in output_for_tray

i3bar/src/xcb.c

index 66003425af864063fbee0b30b250aa8d1920e4f4..d43a4bdd5373b53d1d16bb9dee8cdf0ae6afd945 100644 (file)
@@ -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;
@@ -758,58 +761,16 @@ static void handle_client_message(xcb_client_message_event_t *event) {
             }
 
             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;
@@ -836,7 +797,7 @@ static void handle_client_message(xcb_client_message_event_t *event) {
             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,
@@ -856,7 +817,7 @@ static void handle_client_message(xcb_client_message_event_t *event) {
             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");
@@ -1609,6 +1570,56 @@ static xcb_void_cookie_t config_strut_partial(i3_output *output) {
                                &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
  *
@@ -1616,7 +1627,6 @@ static xcb_void_cookie_t config_strut_partial(i3_output *output) {
 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) {
@@ -1744,58 +1754,6 @@ void reconfig_windows(bool redraw_bars) {
                 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 |
@@ -1889,6 +1847,19 @@ void reconfig_windows(bool redraw_bars) {
             }
         }
     }
+
+    /* 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;
+    }
 }
 
 /*