2012-01-30 13 views
13

Sto provando a creare un'applicazione Linux - uno screensaver, in questo caso - e si sta dimostrando straordinariamente difficile trovare informazioni sul semplice compito di rendere una finestra a schermo intero. Anche il codice degli screensaver esistenti non fa menzione di come lo gestiscono, e non ho ancora visto nessuna funzione ovvia come XRemoveDecoration().X11/GLX - Modalità schermo intero?

Dopo molte armeggiare intorno, sono riuscito a creare una finestra che è la stessa dimensione del desktop, con questo:

Window win = DefaultRootWindow(disp); 
XWindowAttributes getWinAttr; 
XGetWindowAttributes(disp, win, &getWinAttr); 
win = XCreateWindow(disp, win, 0, 0, getWinAttr.width, getWinAttr.height, 0, vInfo->depth, InputOutput, vInfo->visual, CWBorderPixel|CWColormap|CWEventMask|CWOverrideRedirect, &winAttr); 

Ma che non fa nulla per sbarazzarsi della barra del titolo e le frontiere. So che c'è un modo, ovviamente - ma devo ancora trovare qualcosa che indichi anche in quella direzione che non si basa su altre enormi librerie che vengono gettate in cima (che gli screensaver esistenti non usano sicuramente).

MODIFICA: Si prega di non rimuovere le informazioni dai miei messaggi. C'è una buona ragione per cui ho sottolineato esplicitamente che gli screensaver esistenti non utilizzano librerie opzionali, e questo perché ho analizzato il codice sorgente per gran parte del giorno passato.

Ho scelto la risposta che risponde più direttamente alla domanda e si applica alle applicazioni in generale.

Se hai trovato questa domanda alla ricerca di xscreensavers ... lo stesso vale ancora. Sì, xscreensaver ha la sua API - che è complicata, e in realtà comporta la scrittura di più righe di codice (sì, sul serio). Se vuoi OpenGL nel tuo salvaschermo, devi passare attraverso un altro API (xlockmore, un sistema concorrente) e un livello di compatibilità che lo traduce in xscreensaver.

Tuttavia, xscreensaver è in grado di eseguire qualsiasi programma che può utilizzare finestre di root virtuale (guarda in vroot.h) come screensaver. Quindi il mio consiglio è di farlo - avrai più controllo, nessuna API limitante e una maggiore portabilità. (Un esempio ho guardato può anche compilare per Linux o Windows, con lo stesso file!)

+2

+1 per aver ovviamente svolto alcune ricerche. – Flexo

risposta

10

Un modo è quello di bypassare il window manager:

XSetWindowAttributes wa;              
wa.override_redirect = True;           
XCreateWindow(..., &wa); 
+0

Potresti volere GrabKeyboard con questo per ottenere eventi chiave. – eile

+3

Quello ... funziona davvero. Cercando di rintracciare i tuoi passi, trovo ancora praticamente nessuna risorsa relativa all'uso di quell'interruttore, e nessuno degli X Screensavers sembra averlo ... ma per giunta, funziona davvero! – DigitalMan

1

ho trovato freeglut fullscreen funziona bene, anche quando l'hosting applicazione opengl basata su shader all'interno. Qui il codice interno che viene chiamato (ramo X11 ...). HTH

#define _NET_WM_STATE_TOGGLE 2 
static int fghResizeFullscrToggle(void) 
{ 
    XWindowAttributes attributes; 

    if(glutGet(GLUT_FULL_SCREEN)) { 
     /* restore original window size */ 
     SFG_Window *win = fgStructure.CurrentWindow; 
     fgStructure.CurrentWindow->State.NeedToResize = GL_TRUE; 
     fgStructure.CurrentWindow->State.Width = win->State.OldWidth; 
     fgStructure.CurrentWindow->State.Height = win->State.OldHeight; 

    } else { 
     /* resize the window to cover the entire screen */ 
     XGetWindowAttributes(fgDisplay.Display, 
       fgStructure.CurrentWindow->Window.Handle, 
       &attributes); 

     /* 
     * The "x" and "y" members of "attributes" are the window's coordinates 
     * relative to its parent, i.e. to the decoration window. 
     */ 
     XMoveResizeWindow(fgDisplay.Display, 
       fgStructure.CurrentWindow->Window.Handle, 
       -attributes.x, 
       -attributes.y, 
       fgDisplay.ScreenWidth, 
       fgDisplay.ScreenHeight); 
    } 
    return 0; 
} 

static int fghEwmhFullscrToggle(void) 
{ 
    XEvent xev; 
    long evmask = SubstructureRedirectMask | SubstructureNotifyMask; 

    if(!fgDisplay.State || !fgDisplay.StateFullScreen) { 
     return -1; 
    } 

    xev.type = ClientMessage; 
    xev.xclient.window = fgStructure.CurrentWindow->Window.Handle; 
    xev.xclient.message_type = fgDisplay.State; 
    xev.xclient.format = 32; 
    xev.xclient.data.l[0] = _NET_WM_STATE_TOGGLE; 
    xev.xclient.data.l[1] = fgDisplay.StateFullScreen; 
    xev.xclient.data.l[2] = 0; /* no second property to toggle */ 
    xev.xclient.data.l[3] = 1; /* source indication: application */ 
    xev.xclient.data.l[4] = 0; /* unused */ 

    if(!XSendEvent(fgDisplay.Display, fgDisplay.RootWindow, 0, evmask, &xev)) { 
     return -1; 
    } 
    return 0; 
} 

static int fghToggleFullscreen(void) 
{ 
    /* first try the EWMH (_NET_WM_STATE) method ... */ 
    if(fghEwmhFullscrToggle() != -1) { 
     return 0; 
    } 

    /* fall back to resizing the window */ 
    if(fghResizeFullscrToggle() != -1) { 
     return 0; 
    } 
    return -1; 
} 


#endif /* TARGET_HOST_POSIX_X11 */ 
1

prova a guardare questo per un esempio:

Really Slick Screensaver porta per GLX http://rss-glx.sourceforge.net/

sguardo alla funzione di driver.c createWindow().

+0

Sfortunatamente, questo non sembra molto diverso da quello che ho provato (e manca il override_redirect che ha finito per funzionare), e in qualche modo sembra avere ancora meno commenti su quello che sta succedendo del solito. – DigitalMan

+0

@DigitalMan Leggi INSTALL.xscreensaver. Controlla anche queste FAQ http://www.jwz.org/xscreensaver/faq.html#popup-windows. Come datenwolf pubblicato, sembra che tu stia creando la tua applicazione a schermo intero invece di collegarti al deamon screen saver. – Fred

1

Non è assolutamente difficile. Devi solo aggiungere l'atomo giusto alla lista giusta come descritto here.

2

Il pezzo di informazione che ti manca è che gli screensaver non sono responsabili per andare a schermo intero. Il demone screensaver gestirà la finestra del salvaschermo, la inserirà nel livello della finestra dello screensaver dedicato e la renderà a schermo intero.

Quindi per scrivere uno screensaver sei in chiaro.Se si trattava di scrivere un gioco a schermo intero, è necessario impostare l'attributo Ignora redirezione per impedire che la finestra venga gestita dal WM e farlo coprire all'intero schermo.

+0

Questo sembra essere il caso nei moduli xscreensaver di default, sì, ma i componenti aggiuntivi di OpenGL sembrano creare universalmente le proprie finestre. – DigitalMan

+0

@DigitalMan: Creazione finestre! = Gestione finestre. In effetti il ​​demone xscreensaver agisce come un gestore di finestre, ma solo per la finestra di salvaschermo. L'estensione X-Screensaver dichiara un ulteriore ordinamento di root window, che è sempre in cima a tutte le altre finestre e il demone screensaver è responsabile dello spostamento della finestra del programma effetti lì. – datenwolf

1

Il modo migliore e più semplice per ottenerlo è utilizzare la specifica ICCCM atom che funzionerà per i Window Manager più recenti. Basta usare il codice seguente:

Atom wm_state = XInternAtom (display, "_NET_WM_STATE", true); 
Atom wm_fullscreen = XInternAtom (display, "_NET_WM_STATE_FULLSCREEN", true); 

XChangeProperty(display, window, wm_state, XA_ATOM, 32, 
       PropModeReplace, (unsigned char *)&wm_fullscreen, 1); 

La finestra può essere trasparente, in caso affermativo, basta usare la funzione XSetBackground() dove serve ed è fatta.

Problemi correlati