]> git.sesse.net Git - vlc/blob - plugins/gnome/intf_gnome.c
The input-II. (more info by mail in about an hour)
[vlc] / plugins / gnome / intf_gnome.c
1 /*****************************************************************************
2  * intf_gnome.c: Gnome interface
3  *****************************************************************************
4  * Copyright (C) 1999, 2000 VideoLAN
5  *
6  * Authors:
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  * 
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
21  *****************************************************************************/
22
23 /*****************************************************************************
24  * Preamble
25  *****************************************************************************/
26 #include "defs.h"
27
28 #include <errno.h>                                                 /* ENOMEM */
29 #include <stdlib.h>                                                /* free() */
30 #include <string.h>                                            /* strerror() */
31 #include <sys/types.h>                        /* on BSD, uio.h needs types.h */
32 #include <sys/uio.h>                                          /* for input.h */
33
34 #include <X11/Xlib.h>
35 #include <X11/Xutil.h>
36 #include <X11/keysym.h>
37
38 #include "config.h"
39 #include "common.h"
40 #include "threads.h"
41 #include "mtime.h"
42 #include "plugins.h"
43
44 #include "stream_control.h"
45 #include "input_ext-intf.h"
46
47 #include "video.h"
48 #include "video_output.h"
49
50 #include "audio_output.h" /* needed for mute */
51
52 #include "intf_msg.h"
53 #include "interface.h"
54
55 #include "main.h"
56
57 #include <stdio.h>
58
59 #include <gnome.h>
60
61 #include "intf_gnome_thread.h"
62 #include "intf_gnome.h"
63 #include "intf_gnome_interface.h"
64 #include "intf_gnome_support.h"
65
66 /*****************************************************************************
67  * intf_GnomeCreate: initialize and create window
68  *****************************************************************************/
69 int intf_GnomeCreate( intf_thread_t *p_intf )
70 {
71     char       *psz_display;
72
73     /* Allocate instance and initialize some members */
74     p_intf->p_sys = malloc( sizeof( intf_sys_t ) );
75     if( p_intf->p_sys == NULL )
76     {
77         intf_ErrMsg("error: %s\n", strerror(ENOMEM));
78         return( 1 );
79     }
80
81     p_intf->p_sys->p_gnome = malloc( sizeof( gnome_thread_t ) );
82     if( p_intf->p_sys->p_gnome == NULL )
83     {
84         intf_ErrMsg("error: %s\n", strerror(ENOMEM));
85         free( p_intf->p_sys );
86         return( 1 );
87     }
88
89     /* Open display, unsing 'vlc_display' or DISPLAY environment variable */
90     psz_display = XDisplayName( main_GetPszVariable( VOUT_DISPLAY_VAR, NULL ) );
91     p_intf->p_sys->p_display = XOpenDisplay( psz_display );
92     if( !p_intf->p_sys->p_display )                                 /* error */
93     {
94         intf_ErrMsg("error: can't open display %s\n", psz_display );
95         free( p_intf->p_sys->p_gnome );
96         free( p_intf->p_sys );
97         return( 1 );
98     }
99     p_intf->p_sys->i_screen = DefaultScreen( p_intf->p_sys->p_display );
100
101     /* Spawn base window - this window will include the video output window */
102     if( GnomeCreateWindow( p_intf ) )
103     {
104         intf_ErrMsg( "error: can't create output window\n" );
105         XCloseDisplay( p_intf->p_sys->p_display );
106         free( p_intf->p_sys->p_gnome );
107         free( p_intf->p_sys );
108         return( 1 );
109     }
110
111     /* Spawn video output thread */
112     if( p_main->b_video )
113     {
114         p_intf->p_vout = vout_CreateThread( psz_display, p_intf->p_sys->window,
115                                             p_intf->p_sys->i_width,
116                                             p_intf->p_sys->i_height, NULL, 0,
117                                             (void *)&p_intf->p_sys->colormap );
118
119         if( p_intf->p_vout == NULL )                                /* error */
120         {
121             intf_ErrMsg("error: can't create video output thread\n" );
122             GnomeDestroyWindow( p_intf );
123             XCloseDisplay( p_intf->p_sys->p_display );
124             free( p_intf->p_sys->p_gnome );
125             free( p_intf->p_sys );
126             return( 1 );
127         }
128     }
129
130     /* Spawn Gnome thread */
131     p_intf->p_sys->p_gnome->b_die = 0;
132     p_intf->p_sys->p_gnome->b_error = 0;
133     
134     p_intf->p_sys->p_gnome->b_popup_changed = 0;
135     p_intf->p_sys->p_gnome->b_window_changed = 0;
136     p_intf->p_sys->p_gnome->b_playlist_changed = 0;
137
138     vlc_thread_create( &p_intf->p_sys->p_gnome->thread_id, "gnome",
139                        (void *)GnomeThread, p_intf->p_sys->p_gnome );
140
141     /* create basic key bindings */
142     intf_AssignNormalKeys( p_intf );
143     
144
145     /* Disable screen saver and return */
146     p_intf->p_sys->i_ss_count = 1;
147     GnomeDisableScreenSaver( p_intf );
148     return( 0 );
149 }
150
151 /*****************************************************************************
152  * intf_GnomeDestroy: destroy interface window
153  *****************************************************************************/
154 void intf_GnomeDestroy( intf_thread_t *p_intf )
155 {
156     /* Enable screen saver */
157     GnomeEnableScreenSaver( p_intf );
158
159     /* Close input thread, if any (blocking) */
160     if( p_intf->p_input )
161     {
162         input_DestroyThread( p_intf->p_input, NULL );
163     }
164
165     /* Close video output thread, if any (blocking) */
166     if( p_intf->p_vout )
167     {
168         vout_DestroyThread( p_intf->p_vout, NULL );
169     }
170
171     /* Close gnome thread, if any (blocking) */
172     if( p_intf->p_sys->p_gnome->thread_id )
173     {
174         p_intf->p_sys->p_gnome->b_die = 1;
175         intf_Msg( "waiting for Gnome thread to terminate\n" );
176         vlc_thread_join( p_intf->p_sys->p_gnome->thread_id );
177         intf_Msg( "Gnome thread terminated\n" );
178     }
179
180     /* Close main window and display */
181     GnomeDestroyWindow( p_intf );
182     XCloseDisplay( p_intf->p_sys->p_display );
183
184     /* Destroy structures */
185     free( p_intf->p_sys->p_gnome );
186     free( p_intf->p_sys );
187 }
188
189 /*****************************************************************************
190  * intf_GnomeManage: event loop
191  *****************************************************************************/
192 void intf_GnomeManage( intf_thread_t *p_intf )
193 {
194     /* Manage main window */
195     GnomeManageWindow( p_intf );
196
197     /* Manage messages from the Gnome interface */
198     GnomeManageInterface( p_intf );
199 }
200
201 /* following functions are local */
202
203 /*****************************************************************************
204  * GnomeCreateWindow: open and set-up X11 main window
205  *****************************************************************************/
206 static int GnomeCreateWindow( intf_thread_t *p_intf )
207 {
208     XSizeHints              xsize_hints;
209     XSetWindowAttributes    xwindow_attributes;
210     XGCValues               xgcvalues;
211     XEvent                  xevent;
212     boolean_t               b_expose;
213     boolean_t               b_configure_notify;
214     boolean_t               b_map_notify;
215
216     /* Set main window's size */
217     p_intf->p_sys->i_width =  main_GetIntVariable( VOUT_WIDTH_VAR,
218                                                    VOUT_WIDTH_DEFAULT );
219     p_intf->p_sys->i_height = main_GetIntVariable( VOUT_HEIGHT_VAR,
220                                                    VOUT_HEIGHT_DEFAULT );
221
222     /* Prepare window manager hints and properties */
223     xsize_hints.base_width =            p_intf->p_sys->i_width;
224     xsize_hints.base_height =           p_intf->p_sys->i_height;
225     xsize_hints.flags =                 PSize;
226     p_intf->p_sys->wm_protocols =       XInternAtom( p_intf->p_sys->p_display,
227                                                      "WM_PROTOCOLS", True );
228     p_intf->p_sys->wm_delete_window =   XInternAtom( p_intf->p_sys->p_display,
229                                                      "WM_DELETE_WINDOW", True );
230
231     /* Prepare window attributes */
232     xwindow_attributes.backing_store = Always;       /* save the hidden part */
233     xwindow_attributes.background_pixel = WhitePixel( p_intf->p_sys->p_display,
234                                                       p_intf->p_sys->i_screen );
235
236     xwindow_attributes.event_mask = ExposureMask | StructureNotifyMask;
237
238     /* Create the window and set hints - the window must receive ConfigureNotify
239      * events, and, until it is displayed, Expose and MapNotify events. */
240     p_intf->p_sys->window =
241             XCreateWindow( p_intf->p_sys->p_display,
242                            DefaultRootWindow( p_intf->p_sys->p_display ),
243                            0, 0,
244                            p_intf->p_sys->i_width, p_intf->p_sys->i_height, 1,
245                            0, InputOutput, 0,
246                            CWBackingStore | CWBackPixel | CWEventMask,
247                            &xwindow_attributes );
248
249     /* Set window manager hints and properties: size hints, command,
250      * window's name, and accepted protocols */
251     XSetWMNormalHints( p_intf->p_sys->p_display, p_intf->p_sys->window,
252                        &xsize_hints );
253     XSetCommand( p_intf->p_sys->p_display, p_intf->p_sys->window,
254                  p_main->ppsz_argv, p_main->i_argc );
255     XStoreName( p_intf->p_sys->p_display, p_intf->p_sys->window, VOUT_TITLE );
256     if( (p_intf->p_sys->wm_protocols == None)        /* use WM_DELETE_WINDOW */
257         || (p_intf->p_sys->wm_delete_window == None)
258         || !XSetWMProtocols( p_intf->p_sys->p_display, p_intf->p_sys->window,
259                              &p_intf->p_sys->wm_delete_window, 1 ) )
260     {
261         /* WM_DELETE_WINDOW is not supported by window manager */
262         intf_Msg("error: missing or bad window manager - please exit program kindly.\n");
263     }
264
265     /* Creation of a graphic context that doesn't generate a GraphicsExpose
266      * event when using functions like XCopyArea */
267     xgcvalues.graphics_exposures = False;
268     p_intf->p_sys->gc =  XCreateGC( p_intf->p_sys->p_display, p_intf->p_sys->window,
269                                     GCGraphicsExposures, &xgcvalues);
270
271     /* Send orders to server, and wait until window is displayed - three
272      * events must be received: a MapNotify event, an Expose event allowing
273      * drawing in the window, and a ConfigureNotify to get the window
274      * dimensions. Once those events have been received, only ConfigureNotify
275      * events need to be received. */
276     b_expose = 0;
277     b_configure_notify = 0;
278     b_map_notify = 0;
279     XMapWindow( p_intf->p_sys->p_display, p_intf->p_sys->window);
280     do
281     {
282         XNextEvent( p_intf->p_sys->p_display, &xevent);
283         if( (xevent.type == Expose)
284             && (xevent.xexpose.window == p_intf->p_sys->window) )
285         {
286             b_expose = 1;
287         }
288         else if( (xevent.type == MapNotify)
289                  && (xevent.xmap.window == p_intf->p_sys->window) )
290         {
291             b_map_notify = 1;
292         }
293         else if( (xevent.type == ConfigureNotify)
294                  && (xevent.xconfigure.window == p_intf->p_sys->window) )
295         {
296             b_configure_notify = 1;
297             p_intf->p_sys->i_width = xevent.xconfigure.width;
298             p_intf->p_sys->i_height = xevent.xconfigure.height;
299         }
300     } while( !( b_expose && b_configure_notify && b_map_notify ) );
301
302     XSelectInput( p_intf->p_sys->p_display, p_intf->p_sys->window,
303                   StructureNotifyMask | KeyPressMask | ButtonPressMask );
304
305     if( XDefaultDepth(p_intf->p_sys->p_display, p_intf->p_sys->i_screen) == 8 )
306     {
307         /* Allocate a new palette */
308         p_intf->p_sys->colormap = XCreateColormap( p_intf->p_sys->p_display,
309                               DefaultRootWindow( p_intf->p_sys->p_display ),
310                               DefaultVisual( p_intf->p_sys->p_display,
311                                              p_intf->p_sys->i_screen ),
312                               AllocAll );
313
314         xwindow_attributes.colormap = p_intf->p_sys->colormap;
315         XChangeWindowAttributes( p_intf->p_sys->p_display,
316                                  p_intf->p_sys->window,
317                                  CWColormap, &xwindow_attributes );
318     }
319
320     /* At this stage, the window is open, displayed, and ready to receive data */
321     return( 0 );
322 }
323
324 /*****************************************************************************
325  * GnomeDestroyWindow: destroy X11 main window
326  *****************************************************************************/
327 static void GnomeDestroyWindow( intf_thread_t *p_intf )
328 {
329     XUnmapWindow( p_intf->p_sys->p_display, p_intf->p_sys->window );
330     XFreeGC( p_intf->p_sys->p_display, p_intf->p_sys->gc );
331     XDestroyWindow( p_intf->p_sys->p_display, p_intf->p_sys->window );
332 }
333
334 /*****************************************************************************
335  * GnomeManageWindow: manage X11 main window
336  *****************************************************************************/
337 static void GnomeManageWindow( intf_thread_t *p_intf )
338 {
339     XEvent      xevent;                                         /* X11 event */
340     boolean_t   b_resized;                        /* window has been resized */
341     char        i_key;                                    /* ISO Latin-1 key */
342
343     /* Handle X11 events: ConfigureNotify events are parsed to know if the
344      * output window's size changed, MapNotify and UnmapNotify to know if the
345      * window is mapped (and if the display is useful), and ClientMessages
346      * to intercept window destruction requests */
347     b_resized = 0;
348     while( XCheckWindowEvent( p_intf->p_sys->p_display, p_intf->p_sys->window,
349                               StructureNotifyMask | KeyPressMask |
350                               ButtonPressMask, &xevent ) == True )
351     {
352         /* ConfigureNotify event: prepare  */
353         if( (xevent.type == ConfigureNotify)
354             && ((xevent.xconfigure.width != p_intf->p_sys->i_width)
355                 || (xevent.xconfigure.height != p_intf->p_sys->i_height)) )
356         {
357             /* Update dimensions */
358             b_resized = 1;
359             p_intf->p_sys->i_width = xevent.xconfigure.width;
360             p_intf->p_sys->i_height = xevent.xconfigure.height;
361         }
362         /* MapNotify event: change window status and disable screen saver */
363         else if( xevent.type == MapNotify)
364         {
365             if( (p_intf->p_vout != NULL) && !p_intf->p_vout->b_active )
366             {
367                 GnomeDisableScreenSaver( p_intf );
368                 p_intf->p_vout->b_active = 1;
369             }
370         }
371         /* UnmapNotify event: change window status and enable screen saver */
372         else if( xevent.type == UnmapNotify )
373         {
374             if( (p_intf->p_vout != NULL) && p_intf->p_vout->b_active )
375             {
376                 GnomeEnableScreenSaver( p_intf );
377                 p_intf->p_vout->b_active = 0;
378             }
379         }
380         /* Keyboard event */
381         else if( xevent.type == KeyPress )
382         {
383             if( XLookupString( &xevent.xkey, &i_key, 1, NULL, NULL ) )
384             {
385                 if( intf_ProcessKey( p_intf, i_key ) )
386                 {
387                     intf_DbgMsg( "unhandled key '%c' (%i)\n", (char) i_key, i_key );
388                 }
389             }
390         }
391         /* Mouse click */
392         else if( xevent.type == ButtonPress )
393         {
394             switch( ((XButtonEvent *)&xevent)->button )
395             {
396                 case Button1:
397                     /* in this part we will eventually manage
398                      * clicks for DVD navigation for instance */
399                     break;
400
401                 case Button2:
402                     GnomeTogglePointer( p_intf );
403                     break;
404
405                 case Button3:
406                     /* toggle the menu display */
407                     vlc_mutex_lock( &p_intf->p_sys->p_gnome->change_lock );
408                     p_intf->p_sys->p_gnome->b_popup_changed = 1;
409                     vlc_mutex_unlock( &p_intf->p_sys->p_gnome->change_lock );
410                     break;
411             }
412
413         }
414 #ifdef DEBUG
415         /* Other event */
416         else
417         {
418             intf_DbgMsg( "%p -> unhandled event type %d received\n",
419                          p_intf, xevent.type );
420         }
421 #endif
422     }
423
424     /* ClientMessage event - only WM_PROTOCOLS with WM_DELETE_WINDOW data
425      * are handled - according to the man pages, the format is always 32
426      * in this case */
427     while( XCheckTypedEvent( p_intf->p_sys->p_display,
428                              ClientMessage, &xevent ) )
429     {
430         if( (xevent.xclient.message_type == p_intf->p_sys->wm_protocols)
431             && (xevent.xclient.data.l[0] == p_intf->p_sys->wm_delete_window ) )
432         {
433             p_intf->b_die = 1;
434         }
435         else
436         {
437             intf_DbgMsg( "%p -> unhandled ClientMessage received\n", p_intf );
438         }
439     }
440
441     /*
442      * Handle vout or interface windows resizing
443      */
444     if( p_intf->p_vout != NULL )
445     {
446         if( b_resized )
447         {
448             /* If interface window has been resized, change vout size */
449             intf_DbgMsg( "resizing output window\n" );
450             vlc_mutex_lock( &p_intf->p_vout->change_lock );
451             p_intf->p_vout->i_width =  p_intf->p_sys->i_width;
452             p_intf->p_vout->i_height = p_intf->p_sys->i_height;
453             p_intf->p_vout->i_changes |= VOUT_SIZE_CHANGE;
454             vlc_mutex_unlock( &p_intf->p_vout->change_lock );
455         }
456         else if( (p_intf->p_vout->i_width  != p_intf->p_sys->i_width) ||
457                  (p_intf->p_vout->i_height != p_intf->p_sys->i_height) )
458         {
459            /* If video output size has changed, change interface window size */
460             intf_DbgMsg( "resizing output window\n" );
461             p_intf->p_sys->i_width =    p_intf->p_vout->i_width;
462             p_intf->p_sys->i_height =   p_intf->p_vout->i_height;
463             XResizeWindow( p_intf->p_sys->p_display, p_intf->p_sys->window,
464                            p_intf->p_sys->i_width, p_intf->p_sys->i_height );
465         }
466     }
467 }
468
469 /*****************************************************************************
470  * GnomeEnableScreenSaver: enable screen saver
471  *****************************************************************************
472  * This function enable the screen saver on a display after it had been
473  * disabled by XDisableScreenSaver. Both functions use a counter mechanism to
474  * know wether the screen saver can be activated or not: if n successive calls
475  * are made to XDisableScreenSaver, n successive calls to XEnableScreenSaver
476  * will be required before the screen saver could effectively be activated.
477  *****************************************************************************/
478 void GnomeEnableScreenSaver( intf_thread_t *p_intf )
479 {
480     if( p_intf->p_sys->i_ss_count++ == 0 )
481     {
482         intf_Msg( "Enabling screen saver\n" );
483         XSetScreenSaver( p_intf->p_sys->p_display, p_intf->p_sys->i_ss_timeout,
484                          p_intf->p_sys->i_ss_interval, p_intf->p_sys->i_ss_blanking,
485                          p_intf->p_sys->i_ss_exposure );
486     }
487 }
488
489 /*****************************************************************************
490  * GnomeDisableScreenSaver: disable screen saver
491  *****************************************************************************
492  * See XEnableScreenSaver
493  *****************************************************************************/
494 void GnomeDisableScreenSaver( intf_thread_t *p_intf )
495 {
496     if( --p_intf->p_sys->i_ss_count == 0 )
497     {
498         /* Save screen saver informations */
499         XGetScreenSaver( p_intf->p_sys->p_display, &p_intf->p_sys->i_ss_timeout,
500                          &p_intf->p_sys->i_ss_interval, &p_intf->p_sys->i_ss_blanking,
501                          &p_intf->p_sys->i_ss_exposure );
502
503         /* Disable screen saver */
504         intf_Msg("Disabling screen saver\n");
505         XSetScreenSaver( p_intf->p_sys->p_display, 0,
506                          p_intf->p_sys->i_ss_interval, p_intf->p_sys->i_ss_blanking,
507                          p_intf->p_sys->i_ss_exposure );
508     }
509 }
510
511 /*****************************************************************************
512  * GnomeTogglePointer: hide or show the mouse pointer
513  *****************************************************************************
514  * This function hides the X pointer if it is visible by putting it at
515  * coordinates (32,32) and setting the pointer sprite to a blank one. To
516  * show it again, we disable the sprite and restore the original coordinates.
517  *****************************************************************************/
518 void GnomeTogglePointer( intf_thread_t *p_intf )
519 {
520     static Cursor cursor;
521     static boolean_t b_cursor = 0;
522
523     if( p_intf->p_sys->b_mouse )
524     {
525         p_intf->p_sys->b_mouse = 0;
526
527         if( !b_cursor )
528         {
529             XColor color;
530             Pixmap blank = XCreatePixmap( p_intf->p_sys->p_display,
531                                DefaultRootWindow(p_intf->p_sys->p_display),
532                                1, 1, 1 );
533
534             XParseColor( p_intf->p_sys->p_display,
535                          XCreateColormap( p_intf->p_sys->p_display,
536                                           DefaultRootWindow(
537                                                   p_intf->p_sys->p_display ),
538                                           DefaultVisual(
539                                                   p_intf->p_sys->p_display,
540                                                   p_intf->p_sys->i_screen ),
541                                           AllocNone ),
542                          "black", &color );
543
544             cursor = XCreatePixmapCursor( p_intf->p_sys->p_display,
545                            blank, blank, &color, &color, 1, 1 );
546
547             b_cursor = 1;
548         }
549         XDefineCursor( p_intf->p_sys->p_display,
550                        p_intf->p_sys->window, cursor );
551     }
552     else
553     {
554         p_intf->p_sys->b_mouse = 1;
555
556         XUndefineCursor( p_intf->p_sys->p_display, p_intf->p_sys->window );
557     }
558 }
559
560 /*****************************************************************************
561  * GnomeManageInterface: manage messages from the Gnome interface
562
563  *****************************************************************************
564  * In this function, called approx. 10 times a second, we check what the
565  * Gnome interface wanted to tell us.
566  *****************************************************************************/
567 static void GnomeManageInterface( intf_thread_t *p_intf )
568 {
569     gnome_thread_t *p_gnome = p_intf->p_sys->p_gnome;
570
571     /* lock the change structure */
572     vlc_mutex_lock( &p_gnome->change_lock );
573
574     /* you killed my father, prepare to die */
575     if( p_gnome->b_die )
576     {
577         p_intf->b_die = 1;
578     }
579
580     if( p_gnome->b_activity_changed )
581     {
582         vlc_mutex_lock( &p_intf->p_vout->picture_lock );
583         p_intf->p_vout->b_active = p_gnome->b_activity;
584         /* having to access p_main sucks */
585         p_main->p_aout->b_active = p_gnome->b_activity;
586         vlc_mutex_unlock( &p_intf->p_vout->picture_lock );
587
588         p_gnome->b_activity_changed = 0;
589     }
590
591     /* unlock the change structure */
592     vlc_mutex_unlock( &p_gnome->change_lock );
593 }
594
595 /*****************************************************************************
596  * GnomeManageMain: manage main thread messages
597  *****************************************************************************
598  * In this function, called approx. 10 times a second, we check what the
599  * main program wanted to tell us.
600  *****************************************************************************/
601 static gint GnomeManageMain( gpointer p_data )
602 {
603     gnome_thread_t *p_gnome = (void *)p_data;
604
605     /* lock the change structure */
606     vlc_mutex_lock( &p_gnome->change_lock );
607
608     if( p_gnome->b_die )
609     {
610         /* unlock the change structure */
611         vlc_mutex_unlock( &p_gnome->change_lock );
612
613         /* prepare to die, young man */
614         gtk_main_quit();
615         return( FALSE );
616     }
617
618     /* if the "display popup" flag has changed */
619     if( p_gnome->b_popup_changed )
620     {
621         gnome_popup_menu_do_popup( p_gnome->p_popup,
622                                    NULL, NULL, NULL, NULL );
623         p_gnome->b_popup_changed = 0;
624     }
625
626     /* unlock the change structure */
627     vlc_mutex_unlock( &p_gnome->change_lock );
628
629     return( TRUE );
630 }
631
632 /*****************************************************************************
633  * GnomeThread: special Gnome thread
634  *****************************************************************************
635  * this part of the interface is in a separate thread so that we can call
636  * gtk_main() from within it without annoying the rest of the program.
637  * XXX: the approach may look kludgy, and probably is, but I could not find
638  * a better way to dynamically load a Gnome interface at runtime.
639  *****************************************************************************/
640 void GnomeThread( gnome_thread_t *p_gnome )
641 {
642     /* gnome_init needs to know the command line. We don't care, so we
643      * give it an empty one */
644     char *p_args[] = { };
645
646     /* Sleep to avoid using all CPU - since some interfaces needs to access
647      * keyboard events, a 100ms delay is a good compromise */
648     gtk_timeout_add( INTF_IDLE_SLEEP / 1000, GnomeManageMain, p_gnome );
649  
650     gnome_init( "vlc", VERSION, 1, p_args );
651
652     /* create some useful widgets that will certainly be used */
653     p_gnome->p_window = create_intf_window();
654     p_gnome->p_popup = create_intf_popup( );
655
656     /* we don't create these ones yet because we perhaps won't need them */
657     p_gnome->p_about = NULL;
658     p_gnome->p_playlist = NULL;
659
660     /* store p_sys to keep an eye on it */
661     gtk_object_set_data( GTK_OBJECT(p_gnome->p_window), "p_gnome", p_gnome );
662     gtk_object_set_data( GTK_OBJECT(p_gnome->p_popup), "p_gnome", p_gnome );
663
664     /* show the control window */
665     //gtk_widget_show( p_gnome->p_window );
666
667     /* enter gnome mode */
668     gtk_main();
669 }
670