# Can't create SDL2 window under X11 without root permissions (FreeBSD 13.1)



## rodoco (Oct 14, 2022)

Hello, I'm trying to run a minimal SDL2 window under X11.
When binary is run with sudo, it works.
With standard user permissions, I get an "Inappropriate ioctl for device".
My test user is in the "video" group.

Does someone know why ? 
Thanks for your help.


```
CC = clang++
CFLAGS = -g -std=c++17 -Wunused-variable
drm_cflags = -I/usr/local/include/SDL2 -I/usr/local/include -L/usr/local/lib

targets = sdltest


all: $(targets)

sdltest: sdltest.cpp
    $(CC) $(CFLAGS) $(drm_cflags) -o $@ $^ -lncursesw -lSDL2


.PHONY: clean
clean:
    $(RM) *.o
    $(RM) $(targets)
```


```
#include <SDL.h>
#include <cstdio>
#include <cstring>
#include <string.h>
#include <curses.h>
#include <iostream>
#include <fstream>


// #define DRIVER_NAME "KMSDRM"
#define DRIVER_NAME "x11"
// #define DRIVER_NAME "directfb"
// #define DRIVER_NAME "wayland"

SDL_Window *window = NULL;
SDL_Renderer *renderer = NULL;
WINDOW *win = NULL;
std::ofstream logger("log.txt");


void freeIfNeeded(SDL_Window *window, SDL_Renderer *renderer, WINDOW *win)
{
    if (renderer) SDL_DestroyRenderer(renderer);
    if (window) SDL_DestroyWindow(window);
    if (win) endwin();
    logger.close();
}


int main(int argc, char *argv[])
{

    int ch;
    win = initscr();
    nodelay(win, true);
    noecho();

    SDL_Init(0);

    // Find the driver
    bool init = false;
    for (int i = 0; i < SDL_GetNumVideoDrivers(); i++) {
        const char *name = SDL_GetVideoDriver(i);
        if (strcmp(name, DRIVER_NAME) == 0) {
            SDL_VideoInit(name);
            init = true;
            break;
        }
    }
    if (!init) {
        perror("Couldn't find a suitable video driver !");
        logger << "Couldn't find a suitable video driver !" << std::endl;
        freeIfNeeded(window, renderer, win);
        return -1;
    }

    // logger << "SDL Video Driver selected :" << SDL_GetCurrentVideoDriver() << std::endl;

    SDL_Init(SDL_INIT_EVERYTHING);

    window = SDL_CreateWindow(
            "sdl",
            SDL_WINDOWPOS_UNDEFINED,
            SDL_WINDOWPOS_UNDEFINED,
            640,
            480,
            SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_SHOWN);

    if (window == nullptr) {
        perror("Could not create window !");
        logger << "Could not create window !" << std::endl;
        freeIfNeeded(window, renderer, win);
        return -1;
    }

    // select resolution and refresh rate of the main window
    // i915 kmsdrm : rgba order
    const SDL_DisplayMode mode = { SDL_PIXELTYPE(SDL_PIXELTYPE_ARRAYU32), 640, 480, 75, 0 };
    SDL_SetWindowDisplayMode(window, &mode);

    for (int i = 0; i < SDL_GetNumRenderDrivers(); i++) {
        SDL_RendererInfo info;
        SDL_GetRenderDriverInfo(i, &info);
        logger << "Renderer[" << i << "]=" << info.name << std::endl;
    }

    renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
    if (renderer == nullptr) {
        perror("Could not create renderer !");
        logger << "Could not create renderer !" << std::endl;
        freeIfNeeded(window, renderer, win);
        return -1;
    }

    SDL_RendererInfo rendererInfo;
    SDL_GetRendererInfo(renderer, &rendererInfo);
    logger << "Current renderer" << rendererInfo.name << std::endl;

    SDL_ShowCursor(false);
    SDL_RenderClear(renderer);

    bool loop = true;
    int i = 0;
    while (loop) {

        SDL_Event event;
        while(SDL_PollEvent(&event) != 0) {

            if (event.type == SDL_QUIT) {
                loop = false;
            }

        }

        // KMSDRM : without window manager, keyboard events must be read on term
        // curses keyboard management
        ch = getch();
        if (ch == 'q') {
            loop = false;
        }

        SDL_SetRenderDrawColor(renderer, 0x00, 0x80, 0x80, 0xFF);
        SDL_RenderClear(renderer);

        if (i % 2 == 0)
            SDL_SetRenderDrawColor(renderer, 0xFF, 0xFF, 0xFF, 0xFF);
        else
            SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0xFF);

        SDL_RenderDrawLine(renderer, 0, 0, 640, 480);
        SDL_RenderPresent(renderer);
        SDL_Delay(20);

        i++;
    }

    freeIfNeeded(window, renderer, win);
    SDL_Quit();
}
```


----------



## _martin (Oct 16, 2022)

I couldn't used your code 1:1, I had to adjust the Makefile a bit:
	
	



```
$(CC) $(CFLAGS) $(drm_cflags) -o $@ sdltest.cpp
```
without it I ran into the linking issue:
	
	



```
clang++ -g -std=c++17 -Wunused-variable -I/usr/local/include/SDL2 -I/usr/local/include -L/usr/local/lib -lncursesw -lSDL2 -o sdltest
ld: error: undefined symbol: main
>>> referenced by crt1_c.c:75 (/usr/src/lib/csu/amd64/crt1_c.c:75)
>>>               /usr/lib/crt1.o:(_start)
clang++: error: linker command failed with exit code 1 (use -v to see invocation)
*** Error code 1
```
Also `make clean` doesn't work properly as there's no object files created the whole clean stops on error (rm -f would help).

Anyway, with that change I was able to execute it as normal user, window got displayed with one horizontal, flickering line.


----------



## rodoco (Oct 17, 2022)

Thanks for your reply.
The compilation error with this Makefile is probably due to the make binary used. I use gmake and not the default freebsd make.
Could you tell me which FreeBSD version you are using ?


----------



## rodoco (Oct 17, 2022)

After googling, I found a workaround by setting an environment variable.


> export SDL_VIDEODRIVER=x11


I thought that the 'SDL_VideoInit("x11")' would be sufficient.
Could you tell me if SDL_VIDEODRIVER is set on your user ?


----------



## _martin (Oct 17, 2022)

I'm on a generic `13.1-RELEASE-p2`, with 
	
	



```
# pkg info sdl\*
sdl-1.2.15_15,2
sdl2-2.24.0_1
```
User has no special env set 
	
	



```
$ env|grep -i sdl
$
```


----------



## rodoco (Oct 20, 2022)

Thanks. I've forgot I set this var in my profile:

```
export SDL_VIDEODRIVER=kmsdrm
```
By unsetting it, it works.


----------

