Beispiel #1
0
str *
matcher_next(struct matcher *matcher, const void **ref_return)
{
	struct match *m, **mp;

	while (matcher->matches) {
		/* Process all the exhausted strings */
		mp = &matcher->matches;
		while ((m = *mp)) {
			if (stri_more(m->stri)) {
				/* Advance the match candidate's state */
				unsigned ch = stri_utf8_inc(&m->stri);
				if (!globs_step(matcher->globs, ch, &m->state)){
					/* Failed to advance; reject it */
					*mp = m->next;
					match_free(m);
				}
			} else if (m->flags & MATCH_DEFERRED) {
				/* The string is exhausted, but it's
				 * a deferred string; so expand it now */
				struct match *head, **tail;

				tail = matcher_generate(matcher, &head, m);

				/* Remove the current match (m),
				 * replacing it with the head..tail that
				 * was just generated. We don't return m. */
				*tail = m->next;
				*mp = head;
				match_free(m);
			} else {
				/* Found a real, exhausted string.
				 * First, remove it from the list */
				*mp = m->next;

				/* Next, test if it's a real match */
				const void *ref = globs_is_accept_state(
					matcher->globs, m->state);
				if (ref) {
					/* It's real.
					 * Steal the match.str before freeing */
					str *result = m->str;
					m->str = 0;
					match_free(m);
					if (ref_return) {
						*ref_return = ref;
					}
					return result;
				} else {
					/* Not a match; reject */
					match_free(m);
				}
			}
		}
	}
	return 0;
}
Beispiel #2
0
void findDiffMatches(const File* file, const License* license,
        size_t textStartPosition, size_t searchStartPosition,
        GArray* matches,
        unsigned int maxAllowedDiff, unsigned int minAdjacentMatches) {

  if (!matchNTokens(file->tokens, textStartPosition, file->tokens->len,
          license->tokens, searchStartPosition, license->tokens->len,
          minAdjacentMatches)) {
    return;
  }

  DiffResult* diffResult = findMatchAsDiffs(file->tokens, license->tokens,
          textStartPosition, searchStartPosition,
          maxAllowedDiff, minAdjacentMatches);

  if (diffResult) {
    Match* newMatch = diffResult2Match(diffResult, license);

    if (match_rank(newMatch) > MIN_ALLOWED_RANK)
      g_array_append_val(matches, newMatch);
    else {
      match_free(newMatch);
    }
  }
}
Beispiel #3
0
static int driver_remove_match(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {

        struct bus_match_component *components = NULL;
        _cleanup_free_ char *normalized = NULL;
        Context *context = userdata;
        unsigned n_components = 0;
        Client *c = NULL;
        Match *m = NULL;
        char *arg0;
        uint64_t id;
        int r;

        assert(bus);
        assert(message);
        assert(context);

        r = sd_bus_message_read(message, "s", &arg0);
        if (r < 0)
                return r;

        r = bus_kernel_parse_unique_name(message->sender, &id);
        if (r < 0)
                return r;

        c = hashmap_get(context->clients, &id);
        if (!c)
                return sd_bus_error_setf(error, SD_BUS_ERROR_MATCH_RULE_NOT_FOUND, "You have not registered any matches.");

        r = bus_match_parse(arg0, &components, &n_components);
        if (r < 0) {
                r = sd_bus_error_setf(error, SD_BUS_ERROR_MATCH_RULE_INVALID, "Match rule \"%s\" is not valid", arg0);
                goto finish;
        }

        normalized = bus_match_to_string(components, n_components);
        if (!normalized) {
                r = -ENOMEM;
                goto finish;
        }

        m = hashmap_get(c->matches, normalized);
        if (!m) {
                r = sd_bus_error_setf(error, SD_BUS_ERROR_MATCH_RULE_NOT_FOUND, "Match rule \"%s\" not found.", normalized);
                goto finish;
        }

        bus_remove_match_internal_kernel(bus, id, m->cookie);
        match_free(m);

        r = sd_bus_reply_method_return(message, NULL);

finish:
        bus_match_parse_free(components, n_components);

        if (c->n_matches <= 0)
                client_free(c);

        return r;
}
Beispiel #4
0
void trace_tree_emit_rule(struct xswitch *sw, struct trace_tree *tree)
{
	struct match *ma = match();
	struct action *ac_pi = action();
	action_add(ac_pi, AC_PACKET_IN, 0);
	emit_rule(sw, sw->table0, tree, ma, 1, ac_pi);
	action_free(ac_pi);
	match_free(ma);
}
Beispiel #5
0
/*
 * finds the maximal matches according to match_partialComparator
 * destructively filter matches array: input array and discarded matches are automatically freed
 **/
GArray* filterNonOverlappingMatches(GArray* matches) {
  const guint len = matches->len;

  /* profiling says this is not time critical and worst case is O(n^2) with any algorithm */
  /* instead of removing elements from the array set them to NULL and create a new array at the end */
  for (guint i = 0; i < len; i++) {
    Match* thisMatch = match_array_index(matches, i);
    if (thisMatch == NULL) {
      continue;
    }

    for (guint j = i + 1; j < len; j++) {
      Match* otherMatch = match_array_index(matches, j);
      if (otherMatch == NULL) {
        continue;
      }

      gint comparison = match_partialComparator(thisMatch, otherMatch);

      if (comparison > 0) {
        match_free(otherMatch);
        match_array_index(matches, j) = NULL;
      }
      else if (comparison < 0) {
        match_free(thisMatch);
        match_array_index(matches, i) = NULL;
        break;
      }
    }
  }

  GArray* result = g_array_new(FALSE, FALSE, sizeof(Match*));
  for (guint i = 0; i < len; i++) {
    Match* thisMatch = match_array_index(matches, i);
    if (thisMatch) {
      g_array_append_val(result, thisMatch);
    }
  }

  g_array_free(matches, TRUE);

  return result;
}
Beispiel #6
0
void match_array_free(GArray* matches) {
#if GLIB_CHECK_VERSION(2, 32, 0)
  g_array_set_clear_func(matches, match_destroyNotify);
#else
  for (unsigned int i=0; i< matches->len; ++i) {
    Match* tmp = g_array_index(matches, Match*, i);
    match_free(tmp);
  }
#endif
  g_array_free(matches, TRUE);
}
Beispiel #7
0
static int json_printer_ft1(char *buf, int pos, struct trace_tree *tree)
{
	int i;
	int priority;
	struct trace_tree_V *tv;
	struct trace_tree_T *tt;
	struct trace_tree_D *td;
	struct trace_tree_G *tg;
	struct match *ma;
	struct action *ac_pi;

	switch(tree->type) {
	case TT_L:
	case TT_E:
		return pos;
	case TT_D:
		td = (struct trace_tree_D *)tree;
		return json_printer_ft1(buf, pos, td->t);
	case TT_V:
		tv = (struct trace_tree_V *)tree;
		for(i = 0; i < tv->num_branches; i++) {
			pos = json_printer_ft1(buf, pos, tv->branches[i].tree);
		}
		return pos;
	case TT_T:
		tt = (struct trace_tree_T *)tree;
		pos = json_printer_ft1(buf, pos, tt->f);
		pos = json_printer_ft1(buf, pos, tt->t);
		return pos;
	case TT_G:
		tg = (struct trace_tree_G *)tree;
		priority = 0;
		ac_pi = action();
		action_add(ac_pi, AC_PACKET_IN, 0);
		ma = match();
		pos += sprintf(buf+pos, "{\"tid\":\"%d\",", flow_table_get_tid(tg->ft));
		pos += sprintf(buf+pos, "\"columns\":[\"priority\",\"in_port\",");
		pos += header_print_json(tg->new_spec, buf+pos);
		if(buf[pos-1] == ',')
			pos--;
		pos += sprintf(buf+pos, ",\"actions\"],");
		pos += sprintf(buf+pos, "\"data\":[");
		pos = json_printer_ft(buf, pos, tg->t, ma, &priority, ac_pi, tg->new_spec);
		if(buf[pos-1] == ',')
			pos--;
		pos += sprintf(buf+pos, "]},");
		action_free(ac_pi);
		match_free(ma);
		pos = json_printer_ft1(buf, pos, tg->t);
		return pos;
	}
	assert(0);
}
Beispiel #8
0
void
matcher_free(struct matcher *matcher)
{
	struct match *m, *mnext;

	if (matcher->generator->free) {
	    matcher->generator->free(matcher->gcontext);
	}
	mnext = matcher->matches;
	while ((m = mnext)) {
		mnext = m->next;
		match_free(m);
	}
	free(matcher);
}
Beispiel #9
0
/* helper */
static void init_entry(struct xswitch *sw, struct flow_table *ft)
{
	struct match *ma;
	struct msgbuf *msg;
	struct action *ac;
	int index;
	ma = match();
	ac = action();
	action_add(ac, AC_PACKET_IN, 0);
	index = flow_table_get_entry_index(ft);
	assert(index == 0);
	msg = msg_flow_entry_add(ft, index, 0, ma, ac);
	match_free(ma);
	action_free(ac);
	xswitch_send(sw, msg);
}
Beispiel #10
0
static int match_new(Client *c, struct bus_match_component *components, unsigned n_components, Match **_m) {
        Match *m, *first;
        int r;

        assert(c);
        assert(_m);

        r = hashmap_ensure_allocated(&c->matches, string_hash_func, string_compare_func);
        if (r < 0)
                return r;

        m = new0(Match, 1);
        if (!m)
                return -ENOMEM;

        m->match = bus_match_to_string(components, n_components);
        if (!m->match) {
                r = -ENOMEM;
                goto fail;
        }

        m->cookie = ++c->next_cookie;

        first = hashmap_get(c->matches, m->match);
        LIST_PREPEND(matches, first, m);
        r = hashmap_replace(c->matches, m->match, first);
        if (r < 0) {
                LIST_REMOVE(matches, first, m);
                goto fail;
        }

        m->client = c;
        c->n_matches++;

        *_m = m;
        m = NULL;

        return 0;

fail:
        match_free(m);
        return r;
}
Beispiel #11
0
static void client_free(Client *c) {
        Match *m;

        if (!c)
                return;

        if (c->context) {
                if (c->watch)
                        sd_bus_remove_match(c->context->bus, c->watch, on_name_owner_changed, c);

                assert_se(hashmap_remove(c->context->clients, &c->id) == c);
        }

        while ((m = hashmap_first(c->matches)))
                match_free(m);

        hashmap_free(c->matches);
        free(c->watch);

        free(c);
}
Beispiel #12
0
void do_test() {
Start:
   if (isatty(fileno(stdin)))
      printf("Enter a regular expression:\n\n");
   if (fgets(buf, BUFFER, stdin) == NULL)
      return;
   trim(buf);
   if ((shre = shre_compile(buf)) == NULL) {
      printf("error: %s\n", shre_strerror(shre_er));
      goto Start;
   }
   if (isatty(fileno(stdin)))
      printf("\nEnter text to test the regular expression:\n\n");
   while (fgets(buf, BUFFER, stdin) != NULL) {
      trim(buf);
      if (strcmp(buf, "NEW") == 0) {
         goto Start;
      }
      printf("Pattern:  '%s'\n", shre_expression(shre));
      printf("String:   '%s'\n", buf);
      printf("Match:    ");
      if ((match = shre_search(shre, buf)) == NULL) {
         printf(" None\n\n");
      } else {
         printf("'%s'\n", match_get(match));
         for (int i = 1; i < match_num_groups(match); ++i) {
            printf("Group %2d: ", i);
            char* str = match_group(match, i);
            if (!str) {
               printf(" NULL\n");
            } else {
               printf("'%s'\n", str);
               free(str);
            }
         }
         printf("\n");
         match_free(match);
      }
   }
}
Beispiel #13
0
void match_destroyNotify(gpointer matchP) {
  match_free(*((Match**) matchP));
}
Beispiel #14
0
static int driver_add_match(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {

        struct bus_match_component *components = NULL;
        Context *context = userdata;
        unsigned n_components = 0;
        Match *m = NULL;
        Client *c = NULL;
        char *arg0;
        uint64_t id;
        int r;

        assert(bus);
        assert(message);
        assert(context);

        r = sd_bus_message_read(message, "s", &arg0);
        if (r < 0)
                return r;

        r = bus_kernel_parse_unique_name(message->sender, &id);
        if (r < 0)
                return r;

        r = client_acquire(context, id, &c);
        if (r == -ENOBUFS)
                return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Reached limit of %u clients", CLIENTS_MAX);
        if (r < 0)
                return r;

        if (c->n_matches >= MATCHES_MAX) {
                r = sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Reached limit of %u matches per client", MATCHES_MAX);
                goto fail;
        }

        r = bus_match_parse(arg0, &components, &n_components);
        if (r < 0) {
                r = sd_bus_error_setf(error, SD_BUS_ERROR_MATCH_RULE_INVALID, "Match rule \"%s\" is not valid", arg0);
                goto fail;
        }

        r = match_new(c, components, n_components, &m);
        if (r < 0)
                goto fail;

        r = bus_add_match_internal_kernel(bus, id, components, n_components, m->cookie);
        if (r < 0)
                goto fail;

        bus_match_parse_free(components, n_components);

        return sd_bus_reply_method_return(message, NULL);

fail:
        bus_match_parse_free(components, n_components);

        match_free(m);

        if (c->n_matches <= 0)
                client_free(c);

        return r;
}
Beispiel #15
0
/*
 * Do some sanity checks and then reparent the window.
 *
 */
void manage_window(xcb_window_t window, xcb_get_window_attributes_cookie_t cookie,
                   bool needs_to_be_mapped) {
    xcb_drawable_t d = {window};
    xcb_get_geometry_cookie_t geomc;
    xcb_get_geometry_reply_t *geom;
    xcb_get_window_attributes_reply_t *attr = NULL;

    xcb_get_property_cookie_t wm_type_cookie, strut_cookie, state_cookie,
        utf8_title_cookie, title_cookie,
        class_cookie, leader_cookie, transient_cookie,
        role_cookie, startup_id_cookie, wm_hints_cookie,
        wm_normal_hints_cookie, motif_wm_hints_cookie;

    geomc = xcb_get_geometry(conn, d);

    /* Check if the window is mapped (it could be not mapped when intializing and
       calling manage_window() for every window) */
    if ((attr = xcb_get_window_attributes_reply(conn, cookie, 0)) == NULL) {
        DLOG("Could not get attributes\n");
        xcb_discard_reply(conn, geomc.sequence);
        return;
    }

    if (needs_to_be_mapped && attr->map_state != XCB_MAP_STATE_VIEWABLE) {
        xcb_discard_reply(conn, geomc.sequence);
        goto out;
    }

    /* Don’t manage clients with the override_redirect flag */
    if (attr->override_redirect) {
        xcb_discard_reply(conn, geomc.sequence);
        goto out;
    }

    /* Check if the window is already managed */
    if (con_by_window_id(window) != NULL) {
        DLOG("already managed (by con %p)\n", con_by_window_id(window));
        xcb_discard_reply(conn, geomc.sequence);
        goto out;
    }

    /* Get the initial geometry (position, size, …) */
    if ((geom = xcb_get_geometry_reply(conn, geomc, 0)) == NULL) {
        DLOG("could not get geometry\n");
        goto out;
    }

    uint32_t values[1];

    /* Set a temporary event mask for the new window, consisting only of
     * PropertyChange and StructureNotify. We need to be notified of
     * PropertyChanges because the client can change its properties *after* we
     * requested them but *before* we actually reparented it and have set our
     * final event mask.
     * We need StructureNotify because the client may unmap the window before
     * we get to re-parent it.
     * If this request fails, we assume the client has already unmapped the
     * window between the MapRequest and our event mask change. */
    values[0] = XCB_EVENT_MASK_PROPERTY_CHANGE |
                XCB_EVENT_MASK_STRUCTURE_NOTIFY;
    xcb_void_cookie_t event_mask_cookie =
        xcb_change_window_attributes_checked(conn, window, XCB_CW_EVENT_MASK, values);
    if (xcb_request_check(conn, event_mask_cookie) != NULL) {
        LOG("Could not change event mask, the window probably already disappeared.\n");
        goto out;
    }

#define GET_PROPERTY(atom, len) xcb_get_property(conn, false, window, atom, XCB_GET_PROPERTY_TYPE_ANY, 0, len)

    wm_type_cookie = GET_PROPERTY(A__NET_WM_WINDOW_TYPE, UINT32_MAX);
    strut_cookie = GET_PROPERTY(A__NET_WM_STRUT_PARTIAL, UINT32_MAX);
    state_cookie = GET_PROPERTY(A__NET_WM_STATE, UINT32_MAX);
    utf8_title_cookie = GET_PROPERTY(A__NET_WM_NAME, 128);
    leader_cookie = GET_PROPERTY(A_WM_CLIENT_LEADER, UINT32_MAX);
    transient_cookie = GET_PROPERTY(XCB_ATOM_WM_TRANSIENT_FOR, UINT32_MAX);
    title_cookie = GET_PROPERTY(XCB_ATOM_WM_NAME, 128);
    class_cookie = GET_PROPERTY(XCB_ATOM_WM_CLASS, 128);
    role_cookie = GET_PROPERTY(A_WM_WINDOW_ROLE, 128);
    startup_id_cookie = GET_PROPERTY(A__NET_STARTUP_ID, 512);
    wm_hints_cookie = xcb_icccm_get_wm_hints(conn, window);
    wm_normal_hints_cookie = xcb_icccm_get_wm_normal_hints(conn, window);
    motif_wm_hints_cookie = GET_PROPERTY(A__MOTIF_WM_HINTS, 5 * sizeof(uint64_t));

    DLOG("Managing window 0x%08x\n", window);

    i3Window *cwindow = scalloc(1, sizeof(i3Window));
    cwindow->id = window;
    cwindow->depth = get_visual_depth(attr->visual);

    /* We need to grab buttons 1-3 for click-to-focus and buttons 1-5
     * to allow for mouse bindings using --whole-window to work correctly. */
    xcb_grab_button(conn, false, window, XCB_EVENT_MASK_BUTTON_PRESS,
                    XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_ASYNC, root, XCB_NONE,
                    XCB_BUTTON_INDEX_ANY,
                    XCB_BUTTON_MASK_ANY /* don’t filter for any modifiers */);

    /* update as much information as possible so far (some replies may be NULL) */
    window_update_class(cwindow, xcb_get_property_reply(conn, class_cookie, NULL), true);
    window_update_name_legacy(cwindow, xcb_get_property_reply(conn, title_cookie, NULL), true);
    window_update_name(cwindow, xcb_get_property_reply(conn, utf8_title_cookie, NULL), true);
    window_update_leader(cwindow, xcb_get_property_reply(conn, leader_cookie, NULL));
    window_update_transient_for(cwindow, xcb_get_property_reply(conn, transient_cookie, NULL));
    window_update_strut_partial(cwindow, xcb_get_property_reply(conn, strut_cookie, NULL));
    window_update_role(cwindow, xcb_get_property_reply(conn, role_cookie, NULL), true);
    bool urgency_hint;
    window_update_hints(cwindow, xcb_get_property_reply(conn, wm_hints_cookie, NULL), &urgency_hint);
    border_style_t motif_border_style = BS_NORMAL;
    window_update_motif_hints(cwindow, xcb_get_property_reply(conn, motif_wm_hints_cookie, NULL), &motif_border_style);
    xcb_size_hints_t wm_size_hints;
    if (!xcb_icccm_get_wm_size_hints_reply(conn, wm_normal_hints_cookie, &wm_size_hints, NULL))
        memset(&wm_size_hints, '\0', sizeof(xcb_size_hints_t));
    xcb_get_property_reply_t *type_reply = xcb_get_property_reply(conn, wm_type_cookie, NULL);
    xcb_get_property_reply_t *state_reply = xcb_get_property_reply(conn, state_cookie, NULL);

    xcb_get_property_reply_t *startup_id_reply;
    startup_id_reply = xcb_get_property_reply(conn, startup_id_cookie, NULL);
    char *startup_ws = startup_workspace_for_window(cwindow, startup_id_reply);
    DLOG("startup workspace = %s\n", startup_ws);

    /* check if the window needs WM_TAKE_FOCUS */
    cwindow->needs_take_focus = window_supports_protocol(cwindow->id, A_WM_TAKE_FOCUS);

    /* read the preferred _NET_WM_WINDOW_TYPE atom */
    cwindow->window_type = xcb_get_preferred_window_type(type_reply);

    /* Where to start searching for a container that swallows the new one? */
    Con *search_at = croot;

    if (xcb_reply_contains_atom(type_reply, A__NET_WM_WINDOW_TYPE_DOCK)) {
        LOG("This window is of type dock\n");
        Output *output = get_output_containing(geom->x, geom->y);
        if (output != NULL) {
            DLOG("Starting search at output %s\n", output->name);
            search_at = output->con;
        }

        /* find out the desired position of this dock window */
        if (cwindow->reserved.top > 0 && cwindow->reserved.bottom == 0) {
            DLOG("Top dock client\n");
            cwindow->dock = W_DOCK_TOP;
        } else if (cwindow->reserved.top == 0 && cwindow->reserved.bottom > 0) {
            DLOG("Bottom dock client\n");
            cwindow->dock = W_DOCK_BOTTOM;
        } else {
            DLOG("Ignoring invalid reserved edges (_NET_WM_STRUT_PARTIAL), using position as fallback:\n");
            if (geom->y < (int16_t)(search_at->rect.height / 2)) {
                DLOG("geom->y = %d < rect.height / 2 = %d, it is a top dock client\n",
                     geom->y, (search_at->rect.height / 2));
                cwindow->dock = W_DOCK_TOP;
            } else {
                DLOG("geom->y = %d >= rect.height / 2 = %d, it is a bottom dock client\n",
                     geom->y, (search_at->rect.height / 2));
                cwindow->dock = W_DOCK_BOTTOM;
            }
        }
    }

    DLOG("Initial geometry: (%d, %d, %d, %d)\n", geom->x, geom->y, geom->width, geom->height);

    Con *nc = NULL;
    Match *match = NULL;
    Assignment *assignment;

    /* TODO: two matches for one container */

    /* See if any container swallows this new window */
    nc = con_for_window(search_at, cwindow, &match);
    if (nc == NULL) {
        /* If not, check if it is assigned to a specific workspace */
        if ((assignment = assignment_for(cwindow, A_TO_WORKSPACE))) {
            DLOG("Assignment matches (%p)\n", match);
            Con *assigned_ws = workspace_get(assignment->dest.workspace, NULL);
            nc = con_descend_tiling_focused(assigned_ws);
            DLOG("focused on ws %s: %p / %s\n", assigned_ws->name, nc, nc->name);
            if (nc->type == CT_WORKSPACE)
                nc = tree_open_con(nc, cwindow);
            else
                nc = tree_open_con(nc->parent, cwindow);

            /* set the urgency hint on the window if the workspace is not visible */
            if (!workspace_is_visible(assigned_ws))
                urgency_hint = true;
        } else if (startup_ws) {
            /* If it’s not assigned, but was started on a specific workspace,
             * we want to open it there */
            DLOG("Using workspace on which this application was started (%s)\n", startup_ws);
            nc = con_descend_tiling_focused(workspace_get(startup_ws, NULL));
            DLOG("focused on ws %s: %p / %s\n", startup_ws, nc, nc->name);
            if (nc->type == CT_WORKSPACE)
                nc = tree_open_con(nc, cwindow);
            else
                nc = tree_open_con(nc->parent, cwindow);
        } else {
            /* If not, insert it at the currently focused position */
            if (focused->type == CT_CON && con_accepts_window(focused)) {
                LOG("using current container, focused = %p, focused->name = %s\n",
                    focused, focused->name);
                nc = focused;
            } else
                nc = tree_open_con(NULL, cwindow);
        }
    } else {
        /* M_BELOW inserts the new window as a child of the one which was
         * matched (e.g. dock areas) */
        if (match != NULL && match->insert_where == M_BELOW) {
            nc = tree_open_con(nc, cwindow);
        }

        /* If M_BELOW is not used, the container is replaced. This happens with
         * "swallows" criteria that are used for stored layouts, in which case
         * we need to remove that criterion, because they should only be valid
         * once. */
        if (match != NULL && match->insert_where != M_BELOW) {
            DLOG("Removing match %p from container %p\n", match, nc);
            TAILQ_REMOVE(&(nc->swallow_head), match, matches);
            match_free(match);
        }
    }

    DLOG("new container = %p\n", nc);
    if (nc->window != NULL && nc->window != cwindow) {
        if (!restore_kill_placeholder(nc->window->id)) {
            DLOG("Uh?! Container without a placeholder, but with a window, has swallowed this to-be-managed window?!\n");
        } else {
            /* Remove remaining criteria, the first swallowed window wins. */
            while (!TAILQ_EMPTY(&(nc->swallow_head))) {
                Match *first = TAILQ_FIRST(&(nc->swallow_head));
                TAILQ_REMOVE(&(nc->swallow_head), first, matches);
                match_free(first);
            }
        }
    }
    nc->window = cwindow;
    x_reinit(nc);

    nc->border_width = geom->border_width;

    char *name;
    sasprintf(&name, "[i3 con] container around %p", cwindow);
    x_set_name(nc, name);
    free(name);

    /* handle fullscreen containers */
    Con *ws = con_get_workspace(nc);
    Con *fs = (ws ? con_get_fullscreen_con(ws, CF_OUTPUT) : NULL);
    if (fs == NULL)
        fs = con_get_fullscreen_con(croot, CF_GLOBAL);

    if (xcb_reply_contains_atom(state_reply, A__NET_WM_STATE_FULLSCREEN)) {
        /* If this window is already fullscreen (after restarting!), skip
         * toggling fullscreen, that would drop it out of fullscreen mode. */
        if (fs != nc)
            con_toggle_fullscreen(nc, CF_OUTPUT);
        fs = NULL;
    }

    bool set_focus = false;

    if (fs == NULL) {
        DLOG("Not in fullscreen mode, focusing\n");
        if (!cwindow->dock) {
            /* Check that the workspace is visible and on the same output as
             * the current focused container. If the window was assigned to an
             * invisible workspace, we should not steal focus. */
            Con *current_output = con_get_output(focused);
            Con *target_output = con_get_output(ws);

            if (workspace_is_visible(ws) && current_output == target_output) {
                if (!match || !match->restart_mode) {
                    set_focus = true;
                } else
                    DLOG("not focusing, matched with restart_mode == true\n");
            } else
                DLOG("workspace not visible, not focusing\n");
        } else
            DLOG("dock, not focusing\n");
    } else {
        DLOG("fs = %p, ws = %p, not focusing\n", fs, ws);
        /* Insert the new container in focus stack *after* the currently
         * focused (fullscreen) con. This way, the new container will be
         * focused after we return from fullscreen mode */
        Con *first = TAILQ_FIRST(&(nc->parent->focus_head));
        if (first != nc) {
            /* We only modify the focus stack if the container is not already
             * the first one. This can happen when existing containers swallow
             * new windows, for example when restarting. */
            TAILQ_REMOVE(&(nc->parent->focus_head), nc, focused);
            TAILQ_INSERT_AFTER(&(nc->parent->focus_head), first, nc, focused);
        }
    }

    /* set floating if necessary */
    bool want_floating = false;
    if (xcb_reply_contains_atom(type_reply, A__NET_WM_WINDOW_TYPE_DIALOG) ||
        xcb_reply_contains_atom(type_reply, A__NET_WM_WINDOW_TYPE_UTILITY) ||
        xcb_reply_contains_atom(type_reply, A__NET_WM_WINDOW_TYPE_TOOLBAR) ||
        xcb_reply_contains_atom(type_reply, A__NET_WM_WINDOW_TYPE_SPLASH) ||
        xcb_reply_contains_atom(state_reply, A__NET_WM_STATE_MODAL) ||
        (wm_size_hints.flags & XCB_ICCCM_SIZE_HINT_P_MAX_SIZE &&
         wm_size_hints.flags & XCB_ICCCM_SIZE_HINT_P_MIN_SIZE &&
         wm_size_hints.min_height == wm_size_hints.max_height &&
         wm_size_hints.min_width == wm_size_hints.max_width)) {
        LOG("This window is a dialog window, setting floating\n");
        want_floating = true;
    }

    if (xcb_reply_contains_atom(state_reply, A__NET_WM_STATE_STICKY))
        nc->sticky = true;

    FREE(state_reply);
    FREE(type_reply);

    if (cwindow->transient_for != XCB_NONE ||
        (cwindow->leader != XCB_NONE &&
         cwindow->leader != cwindow->id &&
         con_by_window_id(cwindow->leader) != NULL)) {
        LOG("This window is transient for another window, setting floating\n");
        want_floating = true;

        if (config.popup_during_fullscreen == PDF_LEAVE_FULLSCREEN &&
            fs != NULL) {
            LOG("There is a fullscreen window, leaving fullscreen mode\n");
            con_toggle_fullscreen(fs, CF_OUTPUT);
        } else if (config.popup_during_fullscreen == PDF_SMART &&
                   fs != NULL &&
                   fs->window != NULL) {
            i3Window *transient_win = cwindow;
            while (transient_win != NULL &&
                   transient_win->transient_for != XCB_NONE) {
                if (transient_win->transient_for == fs->window->id) {
                    LOG("This floating window belongs to the fullscreen window (popup_during_fullscreen == smart)\n");
                    set_focus = true;
                    break;
                }
                Con *next_transient = con_by_window_id(transient_win->transient_for);
                if (next_transient == NULL)
                    break;
                /* Some clients (e.g. x11-ssh-askpass) actually set
                 * WM_TRANSIENT_FOR to their own window id, so break instead of
                 * looping endlessly. */
                if (transient_win == next_transient->window)
                    break;
                transient_win = next_transient->window;
            }
        }
    }

    /* dock clients cannot be floating, that makes no sense */
    if (cwindow->dock)
        want_floating = false;

    /* Plasma windows set their geometry in WM_SIZE_HINTS. */
    if ((wm_size_hints.flags & XCB_ICCCM_SIZE_HINT_US_POSITION || wm_size_hints.flags & XCB_ICCCM_SIZE_HINT_P_POSITION) &&
        (wm_size_hints.flags & XCB_ICCCM_SIZE_HINT_US_SIZE || wm_size_hints.flags & XCB_ICCCM_SIZE_HINT_P_SIZE)) {
        DLOG("We are setting geometry according to wm_size_hints x=%d y=%d w=%d h=%d\n",
             wm_size_hints.x, wm_size_hints.y, wm_size_hints.width, wm_size_hints.height);
        geom->x = wm_size_hints.x;
        geom->y = wm_size_hints.y;
        geom->width = wm_size_hints.width;
        geom->height = wm_size_hints.height;
    }

    /* Store the requested geometry. The width/height gets raised to at least
     * 75x50 when entering floating mode, which is the minimum size for a
     * window to be useful (smaller windows are usually overlays/toolbars/…
     * which are not managed by the wm anyways). We store the original geometry
     * here because it’s used for dock clients. */
    if (nc->geometry.width == 0)
        nc->geometry = (Rect){geom->x, geom->y, geom->width, geom->height};

    if (motif_border_style != BS_NORMAL) {
        DLOG("MOTIF_WM_HINTS specifies decorations (border_style = %d)\n", motif_border_style);
        if (want_floating) {
            con_set_border_style(nc, motif_border_style, config.default_floating_border_width);
        } else {
            con_set_border_style(nc, motif_border_style, config.default_border_width);
        }
    }

    if (want_floating) {
        DLOG("geometry = %d x %d\n", nc->geometry.width, nc->geometry.height);
        /* automatically set the border to the default value if a motif border
         * was not specified */
        bool automatic_border = (motif_border_style == BS_NORMAL);

        floating_enable(nc, automatic_border);
    }

    /* explicitly set the border width to the default */
    if (nc->current_border_width == -1) {
        nc->current_border_width = (want_floating ? config.default_floating_border_width : config.default_border_width);
    }

    /* to avoid getting an UnmapNotify event due to reparenting, we temporarily
     * declare no interest in any state change event of this window */
    values[0] = XCB_NONE;
    xcb_change_window_attributes(conn, window, XCB_CW_EVENT_MASK, values);

    xcb_void_cookie_t rcookie = xcb_reparent_window_checked(conn, window, nc->frame, 0, 0);
    if (xcb_request_check(conn, rcookie) != NULL) {
        LOG("Could not reparent the window, aborting\n");
        goto geom_out;
    }

    values[0] = CHILD_EVENT_MASK & ~XCB_EVENT_MASK_ENTER_WINDOW;
    xcb_change_window_attributes(conn, window, XCB_CW_EVENT_MASK, values);
    xcb_flush(conn);

    /* Put the client inside the save set. Upon termination (whether killed or
     * normal exit does not matter) of the window manager, these clients will
     * be correctly reparented to their most closest living ancestor (=
     * cleanup) */
    xcb_change_save_set(conn, XCB_SET_MODE_INSERT, window);

    /* Check if any assignments match */
    run_assignments(cwindow);

    /* 'ws' may be invalid because of the assignments, e.g. when the user uses
     * "move window to workspace 1", but had it assigned to workspace 2. */
    ws = con_get_workspace(nc);

    /* If this window was put onto an invisible workspace (via assignments), we
     * render this workspace. It wouldn’t be rendered in our normal code path
     * because only the visible workspaces get rendered.
     *
     * By rendering the workspace, we assign proper coordinates (read: not
     * width=0, height=0) to the window, which is important for windows who
     * actually use them to position their GUI elements, e.g. rhythmbox. */
    if (ws && !workspace_is_visible(ws)) {
        /* This is a bit hackish: we need to copy the content container’s rect
         * to the workspace, because calling render_con() on the content
         * container would also take the shortcut and not render the invisible
         * workspace at all. However, just calling render_con() on the
         * workspace isn’t enough either — it needs the rect. */
        ws->rect = ws->parent->rect;
        render_con(ws, true);
        /* Disable setting focus, otherwise we’d move focus to an invisible
         * workspace, which we generally prevent (e.g. in
         * con_move_to_workspace). */
        set_focus = false;
    }
    render_con(croot, false);

    /* Send an event about window creation */
    ipc_send_window_event("new", nc);

    if (set_focus && assignment_for(cwindow, A_NO_FOCUS) != NULL) {
        /* The first window on a workspace should always be focused. We have to
         * compare with == 1 because the container has already been inserted at
         * this point. */
        if (con_num_children(ws) == 1) {
            DLOG("This is the first window on this workspace, ignoring no_focus.\n");
        } else {
            DLOG("no_focus was set for con = %p, not setting focus.\n", nc);
            set_focus = false;
        }
    }

    /* Defer setting focus after the 'new' event has been sent to ensure the
     * proper window event sequence. */
    if (set_focus && !nc->window->doesnt_accept_focus && nc->mapped) {
        DLOG("Now setting focus.\n");
        con_focus(nc);
    }

    tree_render();

    /* Windows might get managed with the urgency hint already set (Pidgin is
     * known to do that), so check for that and handle the hint accordingly.
     * This code needs to be in this part of manage_window() because the window
     * needs to be on the final workspace first. */
    con_set_urgency(nc, urgency_hint);

geom_out:
    free(geom);
out:
    free(attr);
    return;
}
Beispiel #16
0
static int emit_rule(struct xswitch *sw, struct flow_table *ft,
		     struct trace_tree *tree, struct match *ma, int priority,
		     struct action *ac_pi)
{
	int i;
	struct trace_tree_L *tl;
	struct trace_tree_V *tv;
	struct trace_tree_T *tt;
	struct trace_tree_D *td;
	struct trace_tree_G *tg;

	struct msgbuf *msg;
	struct match *maa;
	struct action *a;
	char buf[128], buf2[128];

	struct expr *move_expr;
	switch(tree->type) {
	case TT_L:
		tl = (struct trace_tree_L *)tree;
		match_dump(ma, buf, 128);
		action_dump(tl->ac, buf2, 128);
		xdebug("tid %d: %2d, %s, %s\n",
		       flow_table_get_tid(ft), priority, buf, buf2);
		if(tl->index == -1) {
			tl->index = flow_table_get_entry_index(ft);
			msg = msg_flow_entry_add(ft, tl->index, priority, ma, tl->ac);
		} else {
			msg = msg_flow_entry_mod(ft, tl->index, priority, ma, tl->ac);
		}
		xswitch_send(sw, msg);
		return priority + 1;
	case TT_V:
		tv = (struct trace_tree_V *)tree;
		for(i = 0; i < tv->num_branches; i++) {
			maa = match_copy(ma);
			match_add(maa,
				  tv->name,
				  tv->branches[i].value,
				  value_from_64(0xffffffffffffffffull));
			priority = emit_rule(sw, ft, tv->branches[i].tree, maa, priority, ac_pi);
			match_free(maa);
		}
		return priority;
	case TT_T:
		tt = (struct trace_tree_T *)tree;
		priority = emit_rule(sw, ft, tt->f, ma, priority, ac_pi);
		maa = match_copy(ma);
		match_add(maa,
			  tt->name,
			  tt->value,
			  value_from_64(0xffffffffffffffffull));
		action_dump(ac_pi, buf, 128);
		xdebug("tid %d: %2d, BARRIER, %s\n",
		       flow_table_get_tid(ft), priority, buf);
		if(tt->barrier_index == -1) {
			tt->barrier_index = flow_table_get_entry_index(ft);
			msg = msg_flow_entry_add(ft, tt->barrier_index, priority, maa, ac_pi);
		} else {
			msg = msg_flow_entry_mod(ft, tt->barrier_index, priority, maa, ac_pi);
		}
		xswitch_send(sw, msg);
		priority = emit_rule(sw, ft, tt->t, maa, priority + 1, ac_pi);
		match_free(maa);
		return priority;
	case TT_G:
		tg = (struct trace_tree_G *)tree;
		if(tg->ft == NULL) {
			int tid = sw->next_table_id++;
			// add a new table
			tg->ft = header_make_flow_table(tg->new_spec, tid);
			msg = msg_flow_table_add(tg->ft);
			xswitch_send(sw, msg);
			init_entry(sw, tg->ft);
		}
		// insert GOTO_TABLE into orig table
		a = action();
		if(tg->old_spec)
			move_expr = header_get_length(tg->old_spec);
		else
			move_expr = expr_value(0);
		expr_generate_action(move_expr, tg->old_spec, tg->ft, tg->stack_base, a);

		match_dump(ma, buf, 128);
		action_dump(a, buf2, 128);
		xdebug("tid %d: %2d, %s, %s\n",
		       flow_table_get_tid(ft), priority, buf, buf2);

		if(tg->index == -1) {
			tg->index = flow_table_get_entry_index(ft);
			msg = msg_flow_entry_add(ft, tg->index, priority, ma, a);
		} else {
			msg = msg_flow_entry_mod(ft, tg->index, priority, ma, a);
		}
		xswitch_send(sw, msg);
		action_free(a);

		maa = match();
		emit_rule(sw, tg->ft, tg->t, maa, 1, ac_pi);
		match_free(maa);
		return priority + 1;
	case TT_D:
		td = (struct trace_tree_D *)tree;
		return emit_rule(sw, ft, td->t, ma, priority, ac_pi);
	case TT_E:
		return priority;
	}
	assert(0);
}
Beispiel #17
0
static int json_printer_ft(char *buf, int pos,
			   struct trace_tree *tree, struct match *ma, int *priority,
			   struct action *ac_pi, struct header *h)
{
	int i;
	struct trace_tree_L *tl;
	struct trace_tree_V *tv;
	struct trace_tree_T *tt;
	struct trace_tree_D *td;
	struct trace_tree_G *tg;

	struct match *maa;
	struct action *a;
	char buf2[128];

	struct expr *move_expr;
	switch(tree->type) {
	case TT_L:
		tl = (struct trace_tree_L *)tree;
		pos = json_printer_fe(buf, pos, *priority, h, ma, tl->ac);
		(*priority)++;
		return pos;
	case TT_V:
		tv = (struct trace_tree_V *)tree;
		for(i = 0; i < tv->num_branches; i++) {
			maa = match_copy(ma);
			match_add(maa,
				  tv->name,
				  tv->branches[i].value,
				  value_from_64(0xffffffffffffffffull));
			pos = json_printer_ft(buf, pos, tv->branches[i].tree, maa, priority, ac_pi, h);
			match_free(maa);
		}
		return pos;
	case TT_T:
		tt = (struct trace_tree_T *)tree;
		pos = json_printer_ft(buf, pos, tt->f, ma, priority, ac_pi, h);
		maa = match_copy(ma);
		match_add(maa,
			  tt->name,
			  tt->value,
			  value_from_64(0xffffffffffffffffull));
		pos = json_printer_fe(buf, pos, *priority, h, maa, ac_pi);
		(*priority)++;
		pos = json_printer_ft(buf, pos, tt->t, maa, priority, ac_pi, h);
		match_free(maa);
		return pos;
	case TT_G:
		tg = (struct trace_tree_G *)tree;
		// insert GOTO_TABLE into orig table
		a = action();
		if(tg->old_spec)
			move_expr = header_get_length(tg->old_spec);
		else
			move_expr = expr_value(0);
		expr_generate_action(move_expr, tg->old_spec, tg->ft, tg->stack_base, a);

		action_dump(a, buf2, 128);
		pos = json_printer_fe(buf, pos, *priority, h, ma, a);
		action_free(a);
		(*priority)++;
		return pos;
	case TT_D:
		td = (struct trace_tree_D *)tree;
		return json_printer_ft(buf, pos, td->t, ma, priority, ac_pi, h);
	case TT_E:
		return pos;
	}
	assert(0);
}