<commit_before>#undef I3__FILE__
#define I3__FILE__ "startup.c"
/*
 * vim:ts=4:sw=4:expandtab
 *
 * i3 - an improved dynamic tiling window manager
 * © 2009 <NAME> and contributors (see also: LICENSE)
 *
 * startup.c: Startup notification code. Ensures a startup notification context
 *            is setup when launching applications. We store the current
 *            workspace to open windows in that startup notification context on
 *            the appropriate workspace.
 *
 */
#include "all.h"
#include "sd-daemon.h"

#include <sys/types.h>
#include <sys/wait.h>
#include <paths.h>

#define SN_API_NOT_YET_FROZEN 1
#include <libsn/sn-launcher.h>

static TAILQ_HEAD(startup_sequence_head, Startup_Sequence) startup_sequences =
    TAILQ_HEAD_INITIALIZER(startup_sequences);

/*
 * After 60 seconds, a timeout will be triggered for each startup sequence.
 *
 * The timeout will just trigger completion of the sequence, so the normal
 * completion process takes place (startup_monitor_event will free it).
 *
 */
static void startup_timeout(EV_P_ ev_timer *w, int revents) {
    const char *id = sn_launcher_context_get_startup_id(w->data);
    DLOG("Timeout for startup sequence %s\n", id);

    struct Startup_Sequence *current, *sequence = NULL;
    TAILQ_FOREACH(current, &startup_sequences, sequences) {
        if (strcmp(current->id, id) != 0)
            continue;

        sequence = current;
        break;
    }

    /* Unref the context (for the timeout itself, see start_application) */
    sn_launcher_context_unref(w->data);

    if (!sequence) {
        DLOG("Sequence already deleted, nevermind.\n");
        return;
    }

    /* Complete the startup sequence, will trigger its deletion. */
    sn_launcher_context_complete(w->data);
    free(w);
}

/*
 * Some applications (such as Firefox) mark a startup sequence as completed
 * *before* they even map a window. Therefore, we cannot entirely delete the
 * startup sequence once it’s marked as complete. Instead, we’ll mark it for
 * deletion in 30 seconds and use that chance to delete old sequences.
 *
 * This function returns the number of active (!) startup notifications, that
 * is, those which are not marked for deletion yet. This is used for changing
 * the root window cursor.
 *
 */
static int _prune_startup_sequences(void) {
    time_t current_time = time(NULL);
    int active_sequences = 0;

    /* Traverse the list and delete everything which was marked for deletion 30
     * seconds ago or earlier. */
    struct Startup_Sequence *current, *next;
    for (next = TAILQ_FIRST(&startup_sequences);
         next != TAILQ_END(&startup_sequences);) {
        current = next;
        next = TAILQ_NEXT(next, sequences);

        if (current->delete_at == 0) {
            active_sequences++;
            continue;
        }

        if (current_time <= current->delete_at)
            continue;

        startup_sequence_delete(current);
    }

    return active_sequences;
}

/**
 * Deletes a startup sequence, ignoring whether its timeout has elapsed.
 * Useful when e.g. a window is moved between workspaces and its children
 * shouldn't spawn on the original workspace.
 *
 */
void startup_sequence_delete(struct Startup_Sequence *sequence) {
    assert(sequence != NULL);
    DLOG("Deleting startup sequence %s, delete_at = %ld, current_time = %ld\n",
         sequence->id, sequence->delete_at, time(NULL));

    /* Unref the context, will be free()d */
    sn_launcher_context_unref(sequence->context);

    /* Delete our internal sequence */
    TAILQ_REMOVE(&startup_sequences, sequence, sequences);

    free(sequence->id);
    free(sequence->workspace);
    FREE(sequence);
}

/*
 * Starts the given application by passing it through a shell. We use double fork
 * to avoid zombie processes. As the started application’s parent exits (immediately),
 * the application is reparented to init (process-id 1), which correctly handles
 * childs, so we don’t have to do it :-).
 *
 * The shell used to start applications is the system's bourne shell (i.e.,
 * /bin/sh).
 *
 * The no_startup_id flag determines whether a startup notification context
 * (and ID) should be created, which is the default and encouraged behavior.
 *
 */
void start_application(const char *command, bool no_startup_id) {
    SnLauncherContext *context;

    if (!no_startup_id) {
        /* Create a startup notification context to monitor the progress of this
         * startup. */
        context = sn_launcher_context_new(sndisplay, conn_screen);
        sn_launcher_context_set_name(context, "i3");
        sn_launcher_context_set_description(context, "exec command in i3");
        /* Chop off everything starting from the first space (if there are any
         * spaces in the command), since we don’t want the parameters. */
        char *first_word = sstrdup(command);
        char *space = strchr(first_word, ' ');
        if (space)
            *space = '\0';
        sn_launcher_context_initiate(context, "i3", first_word, last_timestamp);
        free(first_word);

        /* Trigger a timeout after 60 seconds */
        struct ev_timer *timeout = scalloc(sizeof(struct ev_timer));
        ev_timer_init(timeout, startup_timeout, 60.0, 0.);
        timeout->data = context;
        ev_timer_start(main_loop, timeout);<commit_msg>Fix warning about potentially uninitialized variable.<commit_after>#undef I3__FILE__
#define I3__FILE__ "startup.c"
/*
 * vim:ts=4:sw=4:expandtab
 *
 * i3 - an improved dynamic tiling window manager
 * © 2009 <NAME> and contributors (see also: LICENSE)
 *
 * startup.c: Startup notification code. Ensures a startup notification context
 *            is setup when launching applications. We store the current
 *            workspace to open windows in that startup notification context on
 *            the appropriate workspace.
 *
 */
#include "all.h"
#include "sd-daemon.h"

#include <sys/types.h>
#include <sys/wait.h>
#include <paths.h>

#define SN_API_NOT_YET_FROZEN 1
#include <libsn/sn-launcher.h>

static TAILQ_HEAD(startup_sequence_head, Startup_Sequence) startup_sequences =
    TAILQ_HEAD_INITIALIZER(startup_sequences);

/*
 * After 60 seconds, a timeout will be triggered for each startup sequence.
 *
 * The timeout will just trigger completion of the sequence, so the normal
 * completion process takes place (startup_monitor_event will free it).
 *
 */
static void startup_timeout(EV_P_ ev_timer *w, int revents) {
    const char *id = sn_launcher_context_get_startup_id(w->data);
    DLOG("Timeout for startup sequence %s\n", id);

    struct Startup_Sequence *current, *sequence = NULL;
    TAILQ_FOREACH(current, &startup_sequences, sequences) {
        if (strcmp(current->id, id) != 0)
            continue;

        sequence = current;
        break;
    }

    /* Unref the context (for the timeout itself, see start_application) */
    sn_launcher_context_unref(w->data);

    if (!sequence) {
        DLOG("Sequence already deleted, nevermind.\n");
        return;
    }

    /* Complete the startup sequence, will trigger its deletion. */
    sn_launcher_context_complete(w->data);
    free(w);
}

/*
 * Some applications (such as Firefox) mark a startup sequence as completed
 * *before* they even map a window. Therefore, we cannot entirely delete the
 * startup sequence once it’s marked as complete. Instead, we’ll mark it for
 * deletion in 30 seconds and use that chance to delete old sequences.
 *
 * This function returns the number of active (!) startup notifications, that
 * is, those which are not marked for deletion yet. This is used for changing
 * the root window cursor.
 *
 */
static int _prune_startup_sequences(void) {
    time_t current_time = time(NULL);
    int active_sequences = 0;

    /* Traverse the list and delete everything which was marked for deletion 30
     * seconds ago or earlier. */
    struct Startup_Sequence *current, *next;
    for (next = TAILQ_FIRST(&startup_sequences);
         next != TAILQ_END(&startup_sequences);) {
        current = next;
        next = TAILQ_NEXT(next, sequences);

        if (current->delete_at == 0) {
            active_sequences++;
            continue;
        }

        if (current_time <= current->delete_at)
            continue;

        startup_sequence_delete(current);
    }

    return active_sequences;
}

/**
 * Deletes a startup sequence, ignoring whether its timeout has elapsed.
 * Useful when e.g. a window is moved between workspaces and its children
 * shouldn't spawn on the original workspace.
 *
 */
void startup_sequence_delete(struct Startup_Sequence *sequence) {
    assert(sequence != NULL);
    DLOG("Deleting startup sequence %s, delete_at = %ld, current_time = %ld\n",
         sequence->id, sequence->delete_at, time(NULL));

    /* Unref the context, will be free()d */
    sn_launcher_context_unref(sequence->context);

    /* Delete our internal sequence */
    TAILQ_REMOVE(&startup_sequences, sequence, sequences);

    free(sequence->id);
    free(sequence->workspace);
    FREE(sequence);
}

/*
 * Starts the given application by passing it through a shell. We use double fork
 * to avoid zombie processes. As the started application’s parent exits (immediately),
 * the application is reparented to init (process-id 1), which correctly handles
 * childs, so we don’t have to do it :-).
 *
 * The shell used to start applications is the system's bourne shell (i.e.,
 * /bin/sh).
 *
 * The no_startup_id flag determines whether a startup notification context
 * (and ID) should be created, which is the default and encouraged behavior.
 *
 */
void start_application(const char *command, bool no_startup_id) {
    SnLauncherContext *context = NULL;

    if (!no_startup_id) {
        /* Create a startup notification context to monitor the progress of this
         * startup. */
        context = sn_launcher_context_new(sndisplay, conn_screen);
        sn_launcher_context_set_name(context, "i3");
        sn_launcher_context_set_description(context, "exec command in i3");
        /* Chop off everything starting from the first space (if there are any
         * spaces in the command), since we don’t want the parameters. */
        char *first_word = sstrdup(command);
        char *space = strchr(first_word, ' ');
        if (space)
            *space = '\0';
        sn_launcher_context_initiate(context, "i3", first_word, last_timestamp);
        free(first_word);

        /* Trigger a timeout after 60 seconds */
        struct ev_timer *timeout = scalloc(sizeof(struct ev_timer));
        ev_timer_init(timeout, startup_timeout, 60.0, 0.);
        timeout->data = context;
        ev_timer_start(main_loop, timeout);
{'fraction_non_alphanumeric': 0.0941859376462878, 'fraction_numerical': 0.0056174515494803855, 'mean_word_length': 3.264271457085828, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 37, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4767166', 'n_tokens_mistral': 3169, 'n_tokens_neox': 3029, 'n_words': 1043}