X-DWM - помогите мне исправить ошибку в C исходном коде - PullRequest
2 голосов
/ 08 апреля 2020

Я использую dwm (6.2) оконный менеджер, и я нашел ошибку, которую хотел бы решить.

Диспетчер окон использует «мастер область» и «область стека» , куда помещено windows:

enter image description here

Можно переместить окно вверху «области стека» в нижнюю часть «мастер-области» , используя ALT + i . Также можно переместить windows из нижней части «мастер-области» обратно в «стек-область» , используя ALT + d .

Теперь в этом случае, если я использую ALT + i , изменится раскладка, и после комбинации клавиш будет два windows в «мастер зона» :

enter image description here

Я повторяю это снова, и теперь в есть три windows "master area" :

enter image description here

Я повторяю это еще раз, и теперь в основной области есть три windows « с шириной 100%:

enter image description here

Если бы в этот момент я решил вернуть windows от мастера " область " в " область стека " Я бы начал нажимать ALT + d и windows немедленно вернул бы обратно к " область стека ". Это работает нормально.

Но я намеренно ошибаюсь и вместо этого нажимаю ALT + i снова, например три больше раз. Похоже, ничего не происходит ...

Но теперь, если я попытаюсь вернуть windows из "мастер области" в "область стека" I сначала нужно нажать ALT + d три больше раз и ничего не произойдет ! И наконец, когда я нажимаю ALT + d в четвертый раз, оконный менеджер вернет первое окно из нижней части «мастер-области» в верхняя часть «области стека» .

Так что это не очень хорошо продумано и должно рассматриваться как ошибка ...


Должно быть какое-то сортировка счетчика в исходном коде, который был увеличен еще три раза при нажатии ALT + i , но он не должен увеличиваться после того, как все windows уже находятся в мастере " area ".


В config.def.h исходном файле (www*1125*) есть часть кода, которой назначены клавиши. И здесь я вижу, что когда пользователь нажимает ALT + i , вызывается функция incnmaster() и передается аргумент .i = +1 (я не понимаю этот аргумент) .

static Key keys[] = {
    /* modifier                     key        function        argument */
    ...
    { MODKEY,                       XK_i,      incnmaster,     {.i = +1 } },
    { MODKEY,                       XK_d,      incnmaster,     {.i = -1 } },
    ... 
};

Key - это структура внутри dwm.c исходного файла (www*1141*):

typedef struct {
    unsigned int mod;
    KeySym keysym;
    void (*func)(const Arg *);
    const Arg arg;
} Key;

Функция incnmaster() определена в dwm.c исходном файле (www*1149*):

void
incnmaster(const Arg *arg)
{
    selmon->nmaster = MAX(selmon->nmaster + arg->i, 0);
    arrange(selmon);
} 

, где arg - указатель на Arg (Arg*), который является объединением (I не совсем понимаю, как обращаться с аргументом .i = +1) :

 typedef union {
    int i;
    unsigned int ui;
    float f;
    const void *v;
 } Arg;

selmon является структурой Monitor:

struct Monitor {
    char ltsymbol[16];
    float mfact;
    int nmaster;
    int num;
    int by;               /* bar geometry */
    int mx, my, mw, mh;   /* screen size */
    int wx, wy, ww, wh;   /* window area  */
    unsigned int seltags;
    unsigned int sellt;
    unsigned int tagset[2];
    int showbar;
    int topbar;
    Client *clients;
    Client *sel;
    Client *stack;
    Monitor *next;
    Window barwin;
    const Layout *lt[2];
};

MAX определяется в отдельном исходном файле util.h (www*1171*) как:

#define MAX(A, B)    ((A) > (B) ? (A) : (B))

, а функция arrange() определяется следующим образом:

 void
 arrange(Monitor *m)
 {
    if (m)
        showhide(m->stack);
    else for (m = mons; m; m = m->next)
        showhide(m->stack);
    if (m) {
        arrangemon(m);
        restack(m);
    } else for (m = mons; m; m = m->next)
        arrangemon(m);
}

I не думайте, что мне нужно копать дальше ...


Теперь я думаю, что мне нужно реализовать своего рода if sentantce в коде C, чтобы предотвратить увеличение selmon->nmaster слишком много, но я немного смущен. Кто-нибудь может помочь?

Ответы [ 2 ]

1 голос
/ 21 апреля 2020

Почему вы держите количество клиентов, когда это связанный список? Вы не можете получить количество клиентов по запросу. Подобный код можно найти патч монокль . Если вам действительно нужно сохранить этот счет самостоятельно (по соображениям производительности), я бы посмотрел в любом месте, где список клиентов изменен с помощью dwm, и спроектировал это изменение для счетчика.

Структура Клиент содержит указатель на «следующее» Клиент, реализация может зависеть от того, когда вы хотите использовать поддержку нескольких головок, но с использованием кода, аналогичного клиенту * c = nexttiled (c -> next), где первая ссылка может быть получена из Monitor путем вызова Client * c = nexttiled (монитор-> клиенты). Если вы посчитаете их в l oop, этого должно быть достаточно.

Если вы хотите продолжать вести подсчет самостоятельно, я бы нашел функции в dwm. c, работающие с клиентом (detach, attach, ... ) и найдите список изменений, в котором вы можете увеличить / уменьшить счетчик на основе выполненной операции.

0 голосов
/ 15 апреля 2020

Никто не ответил, прежде чем я сам смог понять это. Проблема в том, что команда Suckless никогда не реализовывала какой-либо механизм для подсчета количества открытых windows (они называют их клиентами) . Вот почему я добавил член int nclients; в struct Monitor:

struct Monitor {
    char ltsymbol[16];
    float mfact;
    int nmaster;
    int nclients;
    int num;
    int by;               /* bar geometry */
    int mx, my, mw, mh;   /* screen size */
    int wx, wy, ww, wh;   /* window area  */
    unsigned int seltags;
    unsigned int sellt;
    unsigned int tagset[2];
    int showbar;
    int topbar;
    Client *clients;
    Client *sel;
    Client *stack;
    Monitor *next;
    Window barwin;
    const Layout *lt[2];
};

И затем я убедился, что он инициализирован до 0 во время загрузки, добавив m->nclients = 0; в createmon() функцию который я догадался, запускается в начале:

Monitor *
createmon(void)
{
    Monitor *m;

    m = ecalloc(1, sizeof(Monitor));
    m->tagset[0] = m->tagset[1] = 1;
    m->mfact = mfact;
    m->nmaster = nmaster;
    m->nclients = 0;
    m->showbar = showbar;
    m->topbar = topbar;
    m->gappx = gappx;
    m->lt[0] = &layouts[0];
    m->lt[1] = &layouts[1 % LENGTH(layouts)];
    strncpy(m->ltsymbol, layouts[0].symbol, sizeof m->ltsymbol);
    return m;
}

Затем я убедился, что мой счетчик nclients увеличивается, когда появляется новое окно. Я добавил ++selmon->nclients; и arrange(selmon); (чтобы иметь возможность перемещать клиенты в стек / мастер сразу после закрытия одного из них) оператор в начале функции spawn():

void
spawn(const Arg *arg)
{
    ++selmon->nclients;
    arrange(selmon);
    if (arg->v == dmenucmd)
        dmenumon[0] = '0' + selmon->num;
    if (fork() == 0) {
        if (dpy)
            close(ConnectionNumber(dpy));
        setsid();
        execvp(((char **)arg->v)[0], (char **)arg->v);
        fprintf(stderr, "dwm: execvp %s", ((char **)arg->v)[0]);
        perror(" failed");
        exit(EXIT_SUCCESS);
    }
}

Счетчик должен быть уменьшен при закрытии окна. Вот почему я добавил --selmon->nclients; и arrange(selmon); (чтобы иметь возможность перемещать клиенты в стек / мастер сразу после закрытия одного из них) в верхней части функции killclient():

void
killclient(const Arg *arg)
{
    --selmon->nclients;
    arrange(selmon);
    if (!selmon->sel)
        return;
    if (!sendevent(selmon->sel->win, wmatom[WMDelete], NoEventMask, wmatom[WMDelete], CurrentTime, 0 , 0, 0)) {
        XGrabServer(dpy);
        XSetErrorHandler(xerrordummy);
        XSetCloseDownMode(dpy, DestroyAll);
        XKillClient(dpy, selmon->sel->win);
        XSync(dpy, False);
        XSetErrorHandler(xerror);
        XUngrabServer(dpy);
    }
}

Теперь, когда счетчик был настроен, я мог бы использовать его для перезаписи incnmaster() функции следующим образом:

void
incnmaster(const Arg *arg)
{
    if((arg->i > 0) && (selmon->nmaster < selmon->nclients)){
        ++selmon->nmaster;
    }
    if((arg->i < 0) && (selmon->nmaster > 0)){
        --selmon->nmaster;
    }
    arrange(selmon);

}

Обратите внимание. Мой DWM немного исправлен, поэтому некоторые строки могут немного отличаться от ваших, но просто придерживайтесь той же философии, и вы можете это исправить.

Это решение частично работает. Он не работает, только когда я:

A. используйте dmenu

dmenu при запуске можно (a) открыть клиент или (b) ничего не делать. В случае (a) все работает как положено, но в случае, если (b) nmaster и nclients снова становятся не синхронизированными c.

Так, например, если я сделаю сценарий (b) один раз и использую CTRL + i бесконечное время, мне придется использовать CTRL + d один раз, и ничего не произойдет, но если я буду использовать его еще раз, одно окно будет перемещено из основного в стек.

B запустить любое оконное приложение из терминала

Похоже, что DWM не может отслеживать windows, которые запускаются из терминала, и обрабатывает их неправильно ... В этом случае также nmaster и nclients становятся не синхронизированными c.


Кто-нибудь знает, существует ли какая-либо другая функция, кроме spawn, которая выполняется при открытии любого типа окна?

Это все еще не решено!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...