Beispiel #1
0
QTC_EXPORT void*
qtcStrLoadList(const char *str, char delim, char escape, size_t size,
               size_t *_nele, void *buff, size_t max_len,
               QtcListEleLoader loader, void *data)
{
    QTC_RET_IF_FAIL(_nele && size && loader && str, nullptr);
    size_t nele = *_nele;
    size_t offset = 0;
    if (!(buff && nele)) {
        nele = 16;
        buff = malloc(16 * size);
    }
    QtCurve::StrList::forEach(
        str, delim, escape, [&] (const char *str, size_t len) {
            if (nele <= offset) {
                nele += 8;
                buff = (char*)realloc(buff, nele * size);
            }
            if (loader((char*)buff + offset * size, str, len, data)) {
                offset++;
                if (max_len && offset >= max_len) {
                    return false;
                }
            }
            return true;
        });
    *_nele = offset;
    if (!*_nele) {
        free(buff);
        return nullptr;
    }
    return buff;
}
Beispiel #2
0
// WM Move
QTC_EXPORT void
qtcX11MoveTrigger(xcb_window_t wid, uint32_t x, uint32_t y)
{
    QTC_RET_IF_FAIL(wid);
    qtcX11FlushXlib();
    qtcX11CallVoid(ungrab_pointer, XCB_TIME_CURRENT_TIME);
    union {
        char _buff[32];
        xcb_client_message_event_t ev;
    } buff;
    memset(&buff, 0, sizeof(buff));
    // ...Taken from bespin...
    // stolen... errr "adapted!" from QSizeGrip
    // Well now it is "ported"
    xcb_client_message_event_t *xev = &buff.ev;
    xev->response_type = XCB_CLIENT_MESSAGE;
    xev->format = 32;
    xev->window = wid;
    xev->type = qtc_x11_net_wm_moveresize;
    xev->data.data32[0] = x;
    xev->data.data32[1] = y;
    xev->data.data32[2] = 8; // NET::Move
    xev->data.data32[3] = XCB_KEY_BUT_MASK_BUTTON_1;
    qtcX11SendEvent(false, qtc_root_window,
                    XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY |
                    XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, xev);
    qtcX11Flush();
}
Beispiel #3
0
QTC_EXPORT void
qtcX11ShadowUninstall(xcb_window_t win)
{
    QTC_RET_IF_FAIL(win);
    qtcX11CallVoid(delete_property, win, qtc_x11_kde_net_wm_shadow);
    qtcX11Flush();
}
Beispiel #4
0
QTC_EXPORT void
qtcX11ShadowInstallWithMargin(xcb_window_t win, const int margins[4])
{
    QTC_RET_IF_FAIL(win);
    if (qtcUnlikely(!margins)) {
        qtcX11ShadowInstall(win);
        return;
    }
    // In principle, I should check for _KDE_NET_WM_SHADOW in _NET_SUPPORTED.
    // However, it's complicated and we will gain nothing.
    xcb_atom_t atom = qtc_x11_kde_net_wm_shadow;
    if (qtc_disp) {
        unsigned long shadow_data[8 + 4];
        memcpy(shadow_data, shadow_data_xlib, 12 * sizeof(unsigned long));
        for (int i = 0;i < 4;i++) {
            shadow_data[i + 8] -= margins[i];
        }
        XChangeProperty(qtc_disp, win, atom, XA_CARDINAL, 32,
                        PropModeReplace, (unsigned char*)shadow_data, 12);
    } else {
        uint32_t shadow_data[8 + 4];
        memcpy(shadow_data, shadow_data_xcb, 12 * sizeof(uint32_t));
        for (int i = 0;i < 4;i++) {
            shadow_data[i + 8] -= margins[i];
        }
        qtcX11ChangeProperty(XCB_PROP_MODE_REPLACE, win, atom,
                             XCB_ATOM_CARDINAL, 32, 12, shadow_data);
        qtcX11Flush();
    }
}
Beispiel #5
0
QTC_EXPORT bool
qtcPopen(const char *file, const char *const *argv,
         unsigned fd_num, QtcPopenFD *fds)
{
    if (qtcUnlikely(!fds || !fd_num)) {
        return qtcSpawn(file, argv, NULL, NULL);
    }
    for (unsigned i = 0;i < fd_num;i++) {
        QTC_RET_IF_FAIL(fds[i].orig >= 0, false);
    }
    int socket_fds[2];
    QTC_RET_IF_FAIL(socketpair(AF_UNIX, SOCK_STREAM, 0,
                               socket_fds) == 0, false);
    qtcFDSetCloexec(socket_fds[0], true);
    qtcFDSetCloexec(socket_fds[1], true);
    QtcPopenData cbdata = {socket_fds[0], fd_num, fds};
    bool res = qtcSpawn(file, argv, qtcPopenCb, &cbdata, qtcPopenFailCb);
    if (!res) {
        shutdown(socket_fds[0], SHUT_RDWR);
        close(socket_fds[0]);
        shutdown(socket_fds[1], SHUT_RDWR);
        close(socket_fds[1]);
        return false;
    }
    close(socket_fds[0]);
    for (unsigned i = 0;i < fd_num;i++) {
        if ((fds[i].replace = qtcRecvFD(socket_fds[1])) < 0) {
            res = false;
            for (unsigned j = 0;j < i;j++) {
                if (fds[i].replace) {
                    shutdown(fds[i].replace, SHUT_RDWR);
                    close(fds[i].replace);
                }
            }
            break;
        }
        if (!(fds[i].mode & (QTC_POPEN_READ | QTC_POPEN_WRITE))) {
            close(fds[i].replace);
            fds[i].replace = -1;
            continue;
        }
    }
    shutdown(socket_fds[1], SHUT_RDWR);
    close(socket_fds[1]);
    return res;
}
Beispiel #6
0
static bool
qtcSignalHandlerSet(int sig)
{
    struct sigaction oact;
    QTC_RET_IF_FAIL(sigaction(sig, NULL, &oact) == 0, false);
    void *handler = ((oact.sa_flags & SA_SIGINFO) ? (void*)oact.sa_handler :
                     (void*)oact.sa_sigaction);
    return qtcNoneOf(handler, SIG_DFL, SIG_IGN);
}
Beispiel #7
0
// Necessary?
void
qtcX11ShadowDestroy()
{
    QTC_RET_IF_FAIL(qtc_xcb_conn);
    for (unsigned int i = 0;
         i < sizeof(shadow_xpixmaps) / sizeof(shadow_xpixmaps[0]);i++) {
        qtcX11CallVoid(free_pixmap, shadow_xpixmaps[i]);
    }
    qtcX11Flush();
}
Beispiel #8
0
void
ShadowHelper::uninstallX11Shadows(QWidget *widget) const
{
    // DO NOT condition compile on QTC_ENABLE_X11.
    // There's no direct linkage on X11 and the following code will just do
    // nothing if X11 is not enabled (either at compile time or at run time).
    QTC_RET_IF_FAIL(qtcX11Enabled());
    if (WId wid = qtcGetWid(widget)) {
        qtcX11ShadowUninstall(wid);
    }
}
Beispiel #9
0
QTC_EXPORT void
qtcX11ShadowInstall(xcb_window_t win)
{
    QTC_RET_IF_FAIL(win);
    // In principle, I should check for _KDE_NET_WM_SHADOW in _NET_SUPPORTED.
    // However, it's complicated and we will gain nothing.
    xcb_atom_t atom = qtc_x11_kde_net_wm_shadow;
    if (qtc_disp) {
        XChangeProperty(qtc_disp, win, atom, XA_CARDINAL, 32, PropModeReplace,
                        (unsigned char*)shadow_data_xlib, 12);
    } else {
        qtcX11ChangeProperty(XCB_PROP_MODE_REPLACE, win, atom,
                             XCB_ATOM_CARDINAL, 32, 12, shadow_data_xcb);
        qtcX11Flush();
    }
}
Beispiel #10
0
void
setup(GtkWidget *widget)
{
    QTC_RET_IF_FAIL(widget);
    GtkWidget *parent = nullptr;

    if (GTK_IS_WINDOW(widget) &&
        !gtk_window_get_decorated(GTK_WINDOW(widget))) {
        return;
    }

    if (GTK_IS_EVENT_BOX(widget) &&
        gtk_event_box_get_above_child(GTK_EVENT_BOX(widget)))
        return;

    parent = gtk_widget_get_parent(widget);

    // widgets used in tabs also must be ignored (happens, unfortunately)
    if (GTK_IS_NOTEBOOK(parent) && Tab::isLabel(GTK_NOTEBOOK(parent), widget))
        return;

    /*
      check event mask (for now we only need to do that for GtkWindow)
      The idea is that if the window has been set to receive button_press
      and button_release events (which is not done by default), it likely
      means that it does something with such events, in which case we should
      not use them for grabbing
    */
    if (oneOf(gTypeName(widget), "GtkWindow") &&
        (gtk_widget_get_events(widget) &
         (GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK)))
        return;

    GtkWidgetProps props(widget);
    if (!isFakeGtk() && !props->wmMoveHacked) {
        props->wmMoveHacked = true;
        gtk_widget_add_events(widget, GDK_BUTTON_RELEASE_MASK |
                              GDK_BUTTON_PRESS_MASK | GDK_LEAVE_NOTIFY_MASK |
                              GDK_BUTTON1_MOTION_MASK);
        registerBtnReleaseHook();
        props->wmMoveDestroy.conn("destroy-event", destroy);
        props->wmMoveStyleSet.conn("style-set", styleSet);
        props->wmMoveMotion.conn("motion-notify-event", motion);
        props->wmMoveLeave.conn("leave-notify-event", leave);
        props->wmMoveButtonPress.conn("button-press-event", buttonPress);
    }
}
Beispiel #11
0
QTC_EXPORT bool
qtcForkBackground(QtcCallback cb, void *data, QtcCallback fail_cb)
{
    QTC_RET_IF_FAIL(cb, false);
    // On linux, waitpid will not accept (discard) SIGCHLD therefore if there is
    // a signal handler registered for SIGCHLD and the child process exit
    // inside waitpid()/wait(), it will be run after the process state is
    // cleared and would therefore block if it call wait() (or waitpid(-1))
    // and if there are other child processes. As a workaround we only call
    // waitpid() if the main program did not set up any signal handlers for
    // SIGCHLD. See (the RATIONALE section of) wait(3P) for more detail.
    pid_t child = fork();
    if (child < 0) {
        return false;
    } else if (child == 0) {
        pid_t grandchild = fork();
        if (grandchild < 0) {
            qtcCall(fail_cb, data);
            _exit(1);
        } else if (grandchild == 0) {
            /* grandchild */
            cb(data);
            _exit(0);
        } else {
            _exit(0);
        }
        return true;
    } else {
        /* parent */
        if (qtcSignalHandlerSet(SIGCHLD)) {
            // If we create a child process, the signal handler will recieve
            // the signal anyway (and there is no way to only block SIGCHLD
            // only for our child process). Since the signal handler may
            // hang and should already take care of getting rid of
            // zombie processes, we do not call waitpid in this case....
            return true;
        }
        // If SIGCHLD is ignored, waitpid will return -1 with errno
        // set to ECHILD, treat this as success (good enough for our purpose
        // and not likely to fail anyway...)
        int status = 0;
        return ((waitpid(child, &status, 0) > 0 && status == 0) ||
                errno == ECHILD);
    }
}
Beispiel #12
0
// Blur
QTC_EXPORT void
qtcX11BlurTrigger(xcb_window_t wid, bool enable, unsigned prop_num,
                  const uint32_t *props)
{
    QTC_RET_IF_FAIL(wid);
    xcb_atom_t atom = qtc_x11_kde_net_wm_blur_behind_region;
    if (enable) {
        if (qtc_disp) {
            QTC_DEF_LOCAL_BUFF(unsigned long, xlib_props, 256, prop_num);
            for (unsigned i = 0;i < prop_num;i++) {
                xlib_props.p[i] = props[i];
            }
            XChangeProperty(qtc_disp, wid, atom, XA_CARDINAL, 32,
                            PropModeReplace, (unsigned char*)xlib_props.p,
                            prop_num);
            QTC_FREE_LOCAL_BUFF(xlib_props);
        } else {
            qtcX11ChangeProperty(XCB_PROP_MODE_REPLACE, wid, atom,
                                 XCB_ATOM_CARDINAL, 32, prop_num, props);
        }
    } else {
Beispiel #13
0
QTC_EXPORT bool
qtcForkBackground(QtcCallback cb, void *data, QtcCallback fail_cb)
{
    QTC_RET_IF_FAIL(cb, false);
    // On linux, waitpid will not accept (discard) SIGCHLD therefore if there is
    // a signal handler registered for SIGCHLD and the child process exit
    // inside waitpid()/wait(), it will be run after the process state is
    // cleared and would therefore block if it call wait() (or waitpid(-1))
    // and if there are other child processes. As a workaround we use vfork()
    // to block the parent until direct child exit so that waitpid() will always
    // be called after the process exit and would never hang because of signal
    // handler. See (the RATIONALE section of) wait(3P) for more detail.
    pid_t child = vfork();
    if (child < 0) {
        return false;
    } else if (child == 0) {
        pid_t grandchild = fork();
        if (grandchild < 0) {
            qtcCall(fail_cb, data);
            _exit(1);
        } else if (grandchild == 0) {
            /* grandchild */
            cb(data);
            _exit(0);
        } else {
            _exit(0);
        }
        return true;
    } else {
        /* parent */
        // If SIGCHLD is ignored, waitpid will return -1 with errno
        // set to ECHILD, treat this as success (good enough for our purpose
        // and not likely to fail anyway...)
        int status = 0;
        return ((waitpid(child, &status, 0) > 0 && status == 0) ||
                errno == ECHILD);
    }
}
Beispiel #14
0
QTC_EXPORT void
_forEach(const char *str, char delim, char escape,
         const std::function<bool(const char*, size_t)> &func)
{
    QTC_RET_IF_FAIL(str);
    Str::Buff<1024> buff;
    if (qtcUnlikely(escape == delim)) {
        escape = '\0';
    }
    const char key[] = {delim, escape, '\0'};
    const char *p = str;
    while (true) {
        size_t len = 0;
        while (true) {
            size_t sub_len = strcspn(p, key);
            buff.resize(len + sub_len + 2);
            memcpy(buff.get() + len, p, sub_len);
            len += sub_len;
            p += sub_len;
            if (escape && *p == escape) {
                buff[len] = p[1];
                if (qtcUnlikely(!p[1])) {
                    p++;
                    break;
                }
                len++;
                p += 2;
            } else {
                buff[len] = '\0';
                break;
            }
        }
        if (!func(buff.get(), len) || !*p) {
            break;
        }
        p++;
    }
}
Beispiel #15
0
bool
ShadowHelper::installX11Shadows(QWidget *widget)
{
    // DO NOT condition compile on QTC_ENABLE_X11.
    // There's no direct linkage on X11 and the following code will just do
    // nothing if X11 is not enabled (either at compile time or at run time).
    QTC_RET_IF_FAIL(qtcX11Enabled(), false);
    if (WId wid = qtcGetWid(widget)) {
        if (widget->windowType() == Qt::ToolTip &&
            widget->inherits("QBalloonTip")) {
            bool atTop = true;
            int margin = qtcGetBalloonMargin(widget, &atTop);
            int margins[4] = {0, 0, 0, 0};
            // KWin's shadows margin order is top, right, bottom, left..
            margins[atTop ? 0 : 2] = margin;
            qtcX11ShadowInstall(wid, margins);
        } else {
            qtcX11ShadowInstall(wid);
        }
        return true;
    }
    return false;
}
Beispiel #16
0
QTC_EXPORT bool
qtcPopenBuff(const char *file, const char *const argv[],
             unsigned buff_num, QtcPopenBuff *buffs, int timeout)
{
    if (qtcUnlikely(!buffs || !buff_num)) {
        return qtcSpawn(file, argv, NULL, NULL);
    }
    bool need_poll = false;
    for (unsigned i = 0;i < buff_num;i++) {
        QTC_RET_IF_FAIL(buffs[i].orig >= 0, false);
        QTC_RET_IF_FAIL(!(buffs[i].mode & QTC_POPEN_READ &&
                          buffs[i].mode & QTC_POPEN_WRITE), false);
        if (buffs[i].mode & QTC_POPEN_READ ||
            buffs[i].mode & QTC_POPEN_WRITE) {
            need_poll = true;
        }
    }
    QTC_DEF_LOCAL_BUFF(QtcPopenFD, fds, 16, buff_num);
    for (unsigned i = 0;i < buff_num;i++) {
        fds.p[i].orig = buffs[i].orig;
        fds.p[i].replace = -1;
        fds.p[i].mode = buffs[i].mode;
    }
    bool res = qtcPopen(file, argv, buff_num, fds.p);
    if (!res) {
        QTC_FREE_LOCAL_BUFF(fds);
        return false;
    }
    for (unsigned i = 0;i < buff_num;i++) {
        buffs[i].orig = fds.p[i].replace;
        if (fds.p[i].replace >= 0) {
            qtcFDSetNonBlock(fds.p[i].replace, true);
            qtcFDSetCloexec(fds.p[i].replace, true);
        }
    }
    QTC_FREE_LOCAL_BUFF(fds);
    if (!need_poll) {
        return true;
    }
    QTC_DEF_LOCAL_BUFF(struct pollfd, poll_fds, 16, buff_num);
    QTC_DEF_LOCAL_BUFF(int, indexes, 16, buff_num);
    unsigned poll_fd_num = 0;
    for (unsigned i = 0;i < buff_num;i++) {
        if (!(buffs[i].mode & (QTC_POPEN_READ | QTC_POPEN_WRITE))) {
            close(buffs[i].orig);
            continue;
        }
        indexes.p[poll_fd_num] = i;
        struct pollfd *cur_fd = &poll_fds.p[poll_fd_num];
        cur_fd->fd = buffs[i].orig;
        cur_fd->events = (buffs[i].mode & QTC_POPEN_READ) ? POLLIN : POLLOUT;
        poll_fd_num++;
    }
    uint64_t start_time = qtcGetTime();
    int poll_timeout = timeout;
    while (true) {
        int ret = poll(poll_fds.p, poll_fd_num, poll_timeout);
        if (ret == -1) {
            if (errno == EINTR) {
                if (!qtcPopenPollCheckTimeout(start_time, timeout,
                                              &poll_timeout)) {
                    break;
                }
                continue;
            }
            break;
        } else if (ret == 0) {
            break;
        }
        for (unsigned i = 0;i < poll_fd_num;i++) {
            struct pollfd *cur_fd = &poll_fds.p[i];
            if (cur_fd->revents & POLLIN) {
                if (!qtcPopenReadBuff(&buffs[indexes.p[i]])) {
                    cur_fd->events &= ~POLLIN;
                }
            } else if (cur_fd->revents & POLLOUT) {
                if (!qtcPopenWriteBuff(&buffs[indexes.p[i]])) {
                    cur_fd->events &= ~POLLOUT;
                }
            }
            if (cur_fd->revents & (POLLERR | POLLHUP | POLLNVAL) ||
                !(cur_fd->events & (POLLIN | POLLOUT))) {
                shutdown(cur_fd->fd, SHUT_RDWR);
                close(cur_fd->fd);
                poll_fd_num--;
                memmove(cur_fd, cur_fd + 1,
                        (poll_fd_num - i) * sizeof(struct pollfd));
                memmove(indexes.p + i, indexes.p + i + 1,
                        (poll_fd_num - i) * sizeof(int));
                i--;
            }
        }
        if (poll_fd_num <= 0 || !qtcPopenPollCheckTimeout(start_time, timeout,
                                                          &poll_timeout)) {
            break;
        }
    }
    for (unsigned i = 0;i < poll_fd_num;i++) {
        struct pollfd *cur_fd = &poll_fds.p[i];
        shutdown(cur_fd->fd, SHUT_RDWR);
        close(cur_fd->fd);
    }
    QTC_FREE_LOCAL_BUFF(indexes);
    QTC_FREE_LOCAL_BUFF(poll_fds);
    return true;
}