summaryrefslogtreecommitdiffstats
path: root/homescreen/qml/qml.qrc
blob: c25e266628c0fab618c611da31fb9d786eed338a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<RCC>
    <qresource prefix="/">
        <file>Home.qml</file>
        <file>main.qml</file>
        <file>MediaArea.qml</file>
        <file>MediaAreaBlank.qml</file>
        <file>MediaAreaMusic.qml</file>
        <file>MediaAreaRadio.qml</file>
        <file>ShortcutArea.qml</file>
        <file>ShortcutIcon.qml</file>
        <file>StatusArea.qml</file>
        <file>TopArea.qml</file>
        <file>IconItem.qml</file>
    </qresource>
</RCC>
88888 } /* Generic.Output */ .highlight .gp { color: #555555 } /* Generic.Prompt */ .highlight .gs { font-weight: bold } /* Generic.Strong */ .highlight .gu { color: #666666 } /* Generic.Subheading */ .highlight .gt { color: #aa0000 } /* Generic.Traceback */ .highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */ .highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */ .highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */ .highlight .kp { color: #008800 } /* Keyword.Pseudo */ .highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */ .highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */ .highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */ .highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */ .highlight .na { color: #336699 } /* Name.Attribute */ .highlight .nb { color: #003388 } /* Name.Builtin */ .highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */ .highlight .no { color: #003366; font-weight: bold } /* Name.Constant */ .highlight .nd { color: #555555 } /* Name.Decorator */ .highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */ .highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */ .highlight .nl { color: #336699; font-style: italic } /* Name.Label */ .highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */ .highlight .py { color: #336699; font-weight: bold } /* Name.Property */ .highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */ .highlight .nv { color: #336699 } /* Name.Variable */ .highlight .ow { color: #008800 } /* Operator.Word */ .highlight .w { color: #bbbbbb } /* Text.Whitespace */ .highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */ .highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */ .highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */ .highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */ .highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */ .highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */ .highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */ .highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */ .highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */ .highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */ .highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */ .highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */ .highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */ .highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */ }
/* PipeWire AGL Cluster IPC
 *
 * Copyright © 2021 Collabora Ltd.
 *    @author Julian Bouzas <julian.bouzas@collabora.com>
 *
 * SPDX-License-Identifier: MIT
 */

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/epoll.h>
#include <string.h>
#include <errno.h>
#include <assert.h>
#include "private.h"
#include "receiver.h"
#include "icipc.h"

#define MAX_SENDERS 128

struct icipc_receiver {
        struct sockaddr_un addr;
        int socket_fd;

        uint8_t *buffer_read;
        size_t buffer_size;

        EpollThread epoll_thread;
        bool thread_running;

        const struct icipc_receiver_events *events;
        void *events_data;

        /* for subclasses */
        void *user_data;
};

static bool reply_message(
                struct icipc_receiver *self,
                int sender_fd,
                uint8_t * buffer,
                size_t size) {
        return self->events && self->events->handle_message ?
            self->events->handle_message(self, sender_fd, buffer, size,
                                         self->events_data) :
            icipc_socket_write(sender_fd, buffer, size) == (ssize_t) size;
}

static void socket_event_received(EpollThread *t, int fd, void *data) {
        /* sender wants to connect, accept connection */
        struct icipc_receiver *self = data;
        socklen_t addr_size = sizeof(self->addr);
        int sender_fd = accept4(fd, (struct sockaddr *)&self->addr, &addr_size,
                                SOCK_CLOEXEC | SOCK_NONBLOCK);
        struct epoll_event event = {0};
        event.events = EPOLLIN;
        event.data.fd = sender_fd;
        epoll_ctl(t->epoll_fd, EPOLL_CTL_ADD, sender_fd, &event);
        if (self->events && self->events->sender_state)
                self->events->sender_state(self, sender_fd,
                                           ICIPC_RECEIVER_SENDER_STATE_CONNECTED,
                                           self->events_data);
}

static void other_event_received(EpollThread *t, int fd, void *data) {
        struct icipc_receiver *self = data;

        /* sender sends a message, read it and reply */
        ssize_t size =
            icipc_socket_read(fd, &self->buffer_read, &self->buffer_size);
        if (size <= 0) {
                if (size < 0)
                        icipc_log_error("receiver: could not read message: %s",
                                        strerror(errno));
                /* client disconnected */
                epoll_ctl(t->epoll_fd, EPOLL_CTL_DEL, fd, NULL);
                close(fd);
                if (self->events && self->events->sender_state)
                        self->events->sender_state(self, fd,
                                                   ICIPC_RECEIVER_SENDER_STATE_DISCONNECTED,
                                                   self->events_data);
                return;
        }

        /* reply */
        if (!reply_message(self, fd, self->buffer_read, size))
                icipc_log_error("receiver: could not reply message: %s",
                                strerror(errno));

        return;
}

/* API */

struct icipc_receiver *icipc_receiver_new(
                const char *path,
                size_t buffer_size,
                const struct icipc_receiver_events *events,
                void *events_data,
                size_t user_size) {
        struct icipc_receiver *self;
        int res;

        /* check params */
        if (path == NULL || buffer_size == 0)
                return NULL;

        self = calloc(1, sizeof(struct icipc_receiver) + user_size);
        if (self == NULL)
                return NULL;

        self->socket_fd = -1;

        /* set address */
        self->addr.sun_family = AF_LOCAL;
        res =
            icipc_construct_socket_path(path, self->addr.sun_path,
                                        sizeof(self->addr.sun_path));
        if (res < 0)
                goto error;

        unlink(self->addr.sun_path);

        /* create socket */
        self->socket_fd =
            socket(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
        if (self->socket_fd < 0)
                goto error;

        /* bind socket */
        if (bind(self->socket_fd, (struct sockaddr *)&self->addr,
                 sizeof(self->addr)) != 0)
                goto error;

        /* listen socket */
        if (listen(self->socket_fd, MAX_SENDERS) != 0)
                goto error;

        /* alloc buffer read */
        self->buffer_size = buffer_size;
        self->buffer_read = calloc(buffer_size, sizeof(uint8_t));
        if (self->buffer_read == NULL)
                goto error;

        /* init epoll thread */
        if (!icipc_epoll_thread_init(&self->epoll_thread, self->socket_fd,
                                     socket_event_received,
                                     other_event_received, self))
                goto error;

        self->events = events;
        self->events_data = events_data;
        if (user_size > 0)
                self->user_data =
                    (void *)((uint8_t *) self + sizeof(struct icipc_receiver));

        return self;

 error:
        if (self->buffer_read)
                free(self->buffer_read);
        if (self->socket_fd != -1)
                close(self->socket_fd);
        free(self);
        return NULL;
}

void icipc_receiver_free(struct icipc_receiver *self) {
        icipc_receiver_stop(self);

        icipc_epoll_thread_destroy(&self->epoll_thread);
        free(self->buffer_read);
        close(self->socket_fd);
        unlink(self->addr.sun_path);
        free(self);
}

bool icipc_receiver_start(struct icipc_receiver *self) {
        if (icipc_receiver_is_running(self))
                return true;

        self->thread_running = icipc_epoll_thread_start(&self->epoll_thread);
        return self->thread_running;
}

void icipc_receiver_stop(struct icipc_receiver *self) {
        if (icipc_receiver_is_running(self)) {
                icipc_epoll_thread_stop(&self->epoll_thread);
                self->thread_running = false;
        }
}

bool icipc_receiver_is_running(struct icipc_receiver *self) {
        return self->thread_running;
}

void *icipc_receiver_get_user_data(struct icipc_receiver *self) {
        return self->user_data;
}