2015-07-21 24 views
60

Sto cercando di creare un piccolo window manager (solo per divertimento), ma sto avendo problemi nel gestire le finestre create da Firefox (solo con tale domanda, altre applicazioni funziona bene)Xlib e Firefox comportamento

Il problema è che, dopo aver lanciato Firefox e aggiunto la mia decorazione, sembra funzionare bene, ma se per esempio provo a fare clic sul pulsante del menu, la finestra (secondaria) non viene visualizzata.

Quello che sembra accadere è che dopo il clic, un evento ClientMessage è sparato con i seguenti valori:

Data: (null) 
Data: _NET_WM_STATE_HIDDEN 
Data: (null) 
Data: (null) 
Data: (null) 

Ora il problema è che non so come mostrare la finestra, quale finestra. Ho provato con:

  • XRaiseWindow
  • XMapWindow
  • Ho cercato di ottenere la finestra transitoria e mostrarlo

ma senza successo. Quello che non capisco è che se questo messaggio client è generato dalla sottofinestra del menu o meno.

Come si visualizza una finestra in _NET_WM_STATE_HIDDEN?

Un altro problema strano è che dopo aver ricevuto ClientMessage, ricevo sempre 2 eventi UnMapNotify.

Ho anche un'altra domanda, se voglio mostrare il "File, Modifica" MENU (in Firefox sembra, se non ricordo male, quando si preme il tasto Alt.

Forse Firefox crea un albero di ? finestre

Questo è il ciclo in cui ho gestire gli eventi:

while(1){ 
    XNextEvent(display, &local_event); 
    switch(local_event.type){ 
     case ConfigureNotify: 
      configure_notify_handler(local_event, display); 
     break; 
     case MotionNotify: 
      motion_handler(local_event, display); 
     break; 
     case CreateNotify: 
      cur_win = local_event.xcreatewindow.window; 
      char *window_name; 
      XFetchName(display, cur_win, &window_name); 
      printf("Window name: %s\n", window_name); 
      if(window_name!=NULL){ 
       if(!strcmp(window_name, "Parent")){ 
        printf("Adding borders\n"); 
        XSetWindowBorderWidth(display, cur_win, BORDER_WIDTH); 
       } 
       XFree(window_name); 
      } 
     break; 
     case MapNotify: 
      map_notify_handler(local_event,display, infos); 
     break; 
     case UnmapNotify: 
      printf("UnMapNotify\n"); 
     break; 
     case DestroyNotify: 
      printf("Destroy Event\n"); 
      destroy_notify_handler(local_event,display); 
     break; 
     case ButtonPress: 
      printf("Event button pressed\n"); 
      button_handler(local_event, display, infos); 
     break; 
     case KeyPress: 
      printf("Keyboard key pressed\n"); 
      keyboard_handler(local_event, display); 
     break; 
     case ClientMessage: 
      printf("------------ClientMessage\n"); 
      printf("\tMessage: %s\n", XGetAtomName(display,local_event.xclient.message_type)); 
      printf("\tFormat: %d\n", local_event.xclient.format); 
      Atom *atoms = (Atom *)local_event.xclient.data.l; 
      int i =0; 
      for(i=0; i<=5; i++){ 
       printf("\t\tData %d: %s\n", i, XGetAtomName(display, atoms[i])); 
      } 
      int nchild; 
      Window *child_windows; 
      Window parent_window; 
      Window root_window; 
      XQueryTree(display, local_event.xclient.window, &root_window, &parent_window, &child_windows, &nchild); 
      printf("\tNumber of childs: %d\n", nchild); 
     break; 
    } 

Ora, nella ClientMessage in realtà sto solo cercando di vedere raccogliere alcune informazioni per capire cosa sta succedendo e quello che posso vedere da. il codice sopra, è che la finestra che ha sollevato th L'evento contiene un figlio (di nuovo: è il menu? o no)

Il codice per l'evento MapNotify, in cui aggiungo la decorazione è il seguente:?

void map_notify_handler(XEvent local_event, Display* display, ScreenInfos infos){ 
    printf("----------Map Notify\n"); 
    XWindowAttributes win_attr; 
    char *child_name; 
    XGetWindowAttributes(display, local_event.xmap.window, &win_attr); 
    XFetchName(display, local_event.xmap.window, &child_name); 
    printf("\tAttributes: W: %d - H: %d - Name: %s - ID %lu\n", win_attr.width, win_attr.height, child_name, local_event.xmap.window); 
    Window trans = None;  
    XGetTransientForHint(display, local_event.xmap.window, &trans); 
    printf("\tIs transient: %ld\n", trans); 
    if(child_name!=NULL){ 
     if(strcmp(child_name, "Parent") && local_event.xmap.override_redirect == False){ 
     Window new_win = draw_window_with_name(display, RootWindow(display, infos.screen_num), "Parent", infos.screen_num, 
          win_attr.x, win_attr.y, win_attr.width, win_attr.height+DECORATION_HEIGHT, 0, 
          BlackPixel(display, infos.screen_num)); 
     XMapWindow(display, new_win); 
     XReparentWindow(display,local_event.xmap.window, new_win,0, DECORATION_HEIGHT); 
     set_window_item(local_event.xmap.window, new_win); 
     XSelectInput(display, local_event.xmap.window, StructureNotifyMask); 
     printf("\tParent window id: %lu\n", new_win); 
     put_text(display, new_win, child_name, "9x15", 10, 10, BlackPixel(display,infos.screen_num), WhitePixel(display, infos.screen_num)); 
     } 
    } 
    XFree(child_name); 
} 

Ora qualcuno mi può aiutare con questi problemi? Purtroppo ho già cercato su Google molte volte, ma senza successo.

Per riassumere, i miei problemi sono due: 1. Come visualizzare i sottofinestre da Firefox 2. Come visualizzare il menu File, Modifica.

UPDATE

ho notato qualcosa di strano test Firefox con xev per capire quali eventi vengono generati al fine di mostrare un'applicazione. Ho visto che usando Firefox in unità e usando Firefox in un altro gestore di finestre, gli eventi sparati sono completamente diversi.In Unity Ho solo:

  1. ClientMessage
  2. UnmapNotify

Invece l'utilizzo di Firefox, per esempio con xfce4, i Xevents generati sono di più:

  1. VisiblityNotify (più di uno)
  2. Evento di esposizione (più di uno)

Ma se cerco di abilitare VisibilityChangeMask nel mio wm, ricevo i seguenti eventi:

  • ConfigureNotify
  • ClientMessage
  • MapNotify
  • 2 UnMapNotify

UPDATE 2

Ho provato a leggere le proprietà XWMhints nella finestra ClientMessage (probabilmente la finestra del menu) ed i valori sono:

  • Per le bandiere 67 = InputHint, StateHint, WIndowGroupHint

  • per lo stato iniziale NormalState

UPDATE 3

ho provato a cercare come un nother window manager funziona, e stavo guardando il codice sorgente di calmwm. Quello che capisco è che, quando arriva l'evento ClientMessage, con un messaggio _NET_WM_STATE, aggiorna queste proprietà e, nel caso di _NET_WM_STATE_HIDDEN, cancella questa proprietà, e il risultato sarà che la proprietà verrà cancellata. Così ho provato ad aggiornare il mio codice per eliminare quella proprietà, ma non funziona ancora. In ogni caso il codice aggiornato rilevante in client_message_handler ora assomiglia a questo:

Atom *atoms = (Atom *)local_event.xclient.data.l; 
int i =0; 
for(i=0; i<=5; i++){ 
    printf("\t\tData %d: %s\n", i, XGetAtomName(display, atoms[i])); 
    if(i==1){ 
     printf("\t Deleting Property: _NET_WM_STATE_HIDDEN \n"); 
     XDeleteProperty(display, cur_window, atoms[i]); 
    } 
} 

E 'solo un test, e sono sicuro che i = 1 nel mio caso è la proprietà _NET_WM_STATE_HIDDEN.

Ecco un link al codice sorgente calmwm: https://github.com/chneukirchen/cwm/blob/linux/xevents.c

Così sto ancora bloccato in quel punto.

AGGIORNAMENTO 4

Davvero non so se aiuta, ma ho cercato di leggere gli attributi di finestra nel MapNotify Event, e la finestra map_state è IsViewable (2).

UPDATE 5

ho trovato un problema simile qui a SO, usando Xlib con python: Xlib python: cannot map firefox menus

La soluzione suggerisce di utilizzare XSetInputFocus, ho provato sul mio gestore XMapNotify:

XSetInputFocus(display, local_event.xmap.window, RevertToParent, CurrentTime); 

Ma ancora non aiuta, il menu di Firefox non appare ancora !! E ho lo stesso problema con il tasto destro del mouse.

AGGIORNAMENTO 6

Giocando con xconfigurenotify eventi e unmap evento ho trovato che la: richiesta di Xconfigure dispone di 2 campi della finestra: Finestra e di cui sopra, e quando il il valore xconfigurerequest.window è lo stesso di xunmap Valore finestra.

E anche che xconfigurerequest.above cambia sempre, ma xconfigurerequest.window è sempre lo stesso in tutti gli eventi.

Sembra che xconfigurerequest.above sia correlato al menu che sto tentando di aprire. Per esempio:

  • se tasto destro del mouse su una pagina ottengo un id (sempre lo stesso per ogni successivo clic)
  • Se destra-clik su una scheda, il valore sopra è un altro
  • e lo stesso accade se ho lasciato il menu principale di firefox

Ancora non so se questo aiuti.

Davvero non lo so Qualcuno ha qualche idea?

+3

Il mio amico e io faccio un sacco di x11, gtk, GDK, e altre cose c lib con Firefox. Abbiamo focalizzato una finestra impostando l'hint '_NET_ACTIVE_WINDOW' e anche' XMapRaised': https://gist.github.com/Noitidart/c7be5489fd38f8ecc76b#file-_ff-addon-snippet-x11_focuswindowbynativehandle-js-L280-L283 guarda male di più il tuo problema e anche far sapere al mio amico – yatg

+0

Grazie a @yatg per il tuo commento, ho una domanda sullo snippet di codice che mi hai inviato, il campo l0 è lo stesso campo che in c sarà xclient.data.l0?E perché lo hai impostato su 2? – Ivan

+3

In realtà verifica questo codice molto più pulito: https://github.com/Noitidart/NativeShot/blob/winnt-found-workaround-for-winnt-nondpi-scale/modules/workers/MainWorker.js#L132-L159 fondamentalmente il motivo per cui era 2 è perché questo è il numero magico per '_NET_WM_STATE_TOGGLE' visto qui: https://github.com/Noitidart/NativeShot/blob/winnt-found-workaround-for-winnt-nondpi-scale/modules/ ostypes_x11.jsm # L245 il 'XFlush' è cruciale per l'azione da intraprendere, se' XFlush' non è fatto, non si farà avanti, almeno nel nostro experince, quindi usare 'XFlush' potrebbe essere la tua soluzione fammi sapere come va plz. – yatg

risposta

1

Usa xtruss-un facile da usare X protocollo tracing programma


Panoramica

qualsiasi programmatore abituato a scrivere programmi su Linux o il sistema V-tipo Gli Unix avranno incontrato il programma variamente noto come strace o truss, che monitora un altro programma e produce un registro dettagliato di ogni sys chiama il programma rende - in altre parole, tutte le interazioni del programma con il kernel del sistema operativo. Questo è spesso uno strumento di debug inestimabile e quasi altrettanto educativo.

Quando si tratta di un programma GUI (o piuttosto, il comportamento di un programma relativo alla GUI) che si desidera comprendere o eseguire il debug, il livello di interazione con il kernel del sistema operativo è raramente il più utile. Più utile, si vorrebbe registrare tutte le interazioni del programma con il server X nello stesso modo.

Esistono già programmi che lo faranno. Sono a conoscenza di Xmon e Xtrace.Ma tendono a richiedere un sacco di sforzi per impostare: devi eseguire il programma per stabilire un server di ascolto, quindi organizzare manualmente il programma di destinazione per contattare quello invece del server reale, incluso un po 'di lavoro labiale con xauth. Idealmente, ti piacerebbe rintracciare le operazioni X di un programma in modo altrettanto semplice come tracciare le sue chiamate al sistema del kernel: ti piacerebbe digitare un comando semplice come argomenti nome-programma strace e avere tutto automaticamente gestito per te.

Inoltre, l'output di questi programmi è meno facile da leggere di quanto avrei voluto, con il quale intendo in gran parte che è meno simile di quanto mi piacerebbe. strace ha la buona proprietà di mettere ogni chiamata di sistema e il suo valore di ritorno sulla stessa riga di output, in modo da poter vedere a colpo d'occhio a che cosa ogni risposta è stata una risposta. I monitor del protocollo X, tuttavia, tendono a seguire fedelmente la struttura del protocollo X, il che significa che ogni richiesta e risposta è stampata con un numero di sequenza e devi far combaciare i due in base all'occhio.

Quindi questa pagina presenta xtruss, il mio contributo al campo dei logger del protocollo X. Ha una sintassi della riga di comando simile a strace: nella sua modalità predefinita, si prefissa "xtruss" alla stessa riga di comando che avresti eseguito comunque - e il suo formato di output è anche più simile a strace, mettendo richieste e risposte sullo stesso linea di produzione dove ragionevolmente possibile.

strace supporta anche la funzionalità di collegamento a un processo già in esecuzione e tracciamento dal centro della sua corsa - utile quando qualcosa va storto con un processo di lunga durata che non sapevi in ​​anticipo che stavi per bisogno di rintracciare. xtruss supporta questa stessa funzionalità, tramite l'estensione X RECORD (a condizione che il tuo server X lo supporti, quali sono i moderni X.Org); così in quella modalità, puoi identificare una finestra con il mouse (analogamente ai programmi standard come xwininfo e xkill), e xtruss si collegherà al programma client X che possiede la finestra che hai specificato, e inizierà a tracciarlo.


Descrizione

xtruss è un programma di utilità che registra tutto ciò che passa tra il server X e uno o più programmi X client. In questo è simile a xmon (1), ma intendeva combinare la funzionalità di base di xmon con un'interfaccia molto più simile a strace (1).

Come xmon, xtruss nella sua modalità predefinita funziona impostando un server X proxy, in attesa di connessioni e inoltrandole sul server X reale. Tuttavia, a differenza di xmon, non è necessario gestirli manualmente: non è necessario avviare l'utilità di tracciamento in un terminale e collegarli manualmente ad altri da un altro, a meno che non lo si voglia realmente (nel qual caso il - L'opzione P lo farà). La principale modalità di utilizzo è semplicemente digitare xtruss seguito dalla riga di comando del tuo programma X; xtruss si prenderà automaticamente cura di regolare l'ambiente del nuovo programma in modo che punti al suo server proxy, e (a differenza di xmon) si prenderà cura anche dell'autorizzazione X automaticamente.

Come modalità di utilizzo alternativa, è anche possibile collegare xtruss a un'applicazione X già in esecuzione, se non si è capito che si desidera eseguire il tracciamento fino a quando non è stato avviato. Questa modalità richiede la cooperazione dal server X - in particolare, non può funzionare se il server non supporta l'estensione del protocollo RECORD - ma poiché i server X.Org moderni lo forniscono, è spesso utile.

+0

grazie, darò un'occhiata! :) – Ivan