00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include <ctype.h>
00019 #include <string.h>
00020 #include <stdio.h>
00021 #include <unistd.h>
00022 #include <stdlib.h>
00023 #include <pthread.h>
00024 #include <signal.h>
00025 #include <limits.h>
00026 #include <iostream>
00027 using namespace std;
00028
00029 #include <qsettings.h>
00030 #include <qmessagebox.h>
00031
00032 #include "common.h"
00033 #include "RioMMBrowser.h"
00034 #include "RioError.h"
00035 #include "ConfigData.h"
00036
00037 #define expected_mozilla_version "1.3"
00038
00039
00040
00041 CRioMMBrowser::CRioMMBrowser( char *VideoName,
00042 unsigned int blocksize,
00043 RioBlock numBuffers , struct timeval RTT_average )
00044 : CRioMMSlideShow( VideoName, blocksize, numBuffers , RTT_average )
00045 {
00046
00047 Major = 1;
00048 Minor = 0;
00049
00050
00051 CommandsList = NULL;
00052 NumberOfCommands = 0;
00053
00054
00055 dpy = 0x0;
00056 NetscapeWindow = 0x0;
00057 lock_data = NULL;
00058 tid = 0;
00059 browser_pid = 0;
00060 browserCmdLine = NULL;
00061 }
00062
00063
00064 CRioMMBrowser::~CRioMMBrowser( void )
00065 {
00066 Cleanup();
00067 }
00068
00069
00070 int CRioMMBrowser::init( void )
00071 {
00072 dpy = XOpenDisplay( NULL );
00073 if( dpy == NULL )
00074 return 0;
00075
00076 XA_MOZILLA_VERSION = XInternAtom( dpy, MOZILLA_VERSION_PROP, False );
00077 XA_MOZILLA_LOCK = XInternAtom( dpy, MOZILLA_LOCK_PROP, False );
00078 XA_MOZILLA_COMMAND = XInternAtom( dpy, MOZILLA_COMMAND_PROP, False );
00079 XA_MOZILLA_RESPONSE = XInternAtom( dpy, MOZILLA_RESPONSE_PROP, False );
00080
00081 if( !readSettings() )
00082 writeDefaultSettings();
00083
00084 OpenNetscapeWindow();
00085
00086 return( 1 );
00087 }
00088
00089
00090 int CRioMMBrowser::Cleanup( void )
00091 {
00092 if( NetscapeWindow )
00093 {
00094 if( mozilla_remote_check_window() )
00095 SendCommandToNetscape( "close()" );
00096
00097 if( mozilla_remote_check_window() )
00098 SendCommandToNetscape( "exit()" );
00099
00100 NetscapeWindow = 0;
00101 }
00102
00103 if( dpy )
00104 {
00105 XCloseDisplay( dpy );
00106 dpy = NULL;
00107 }
00108
00109 return 1;
00110 }
00111
00112
00113 void CRioMMBrowser::Stop()
00114 {
00115 CRioMMSlideShow::Stop();
00116 }
00117
00118
00119 bool CRioMMBrowser::ChangeContext( const char *file_name, int slide_number )
00120 {
00121 TString NextFileName;
00122
00123 if( !NetscapeWindow )
00124 NetscapeWindow = mozilla_remote_find_window();
00125
00126 if( !NetscapeWindow || !dpy )
00127 return false;
00128
00129 NextFileName = file_name;
00130 if( NextFileName != CurrentFileName )
00131 {
00132 if( NextFileName.BeginsWith( "LOCAL:" ) )
00133 {
00134 Command = "openFile(" + TempDirectory + "/" +
00135 NextFileName.Substring( strlen( "LOCAL:" ) ) + ")";
00136 }
00137 else
00138 {
00139 Command = "openURL(" + NextFileName + ")";
00140 }
00141
00142 SendCommandToNetscape( Command );
00143 }
00144
00145 CRioMMSlideShow::ChangeContext( file_name, slide_number );
00146
00147 return true;
00148 }
00149
00150 void CRioMMBrowser::SyncSpecific( void )
00151 {
00152 if( dpy )
00153 XSync( dpy, 0 );
00154 }
00155
00156 void CRioMMBrowser::StartBrowser( void )
00157 {
00158 TString url( "file://" );
00159
00160 if( (browser_pid = fork()) != 0 )
00161 {
00162 if( browser_pid < 0 )
00163 {
00164 #ifdef RIO_DEBUG2
00165 RioErr << "fork(). Failed to fork process." << endl;
00166 #endif
00167
00168 return;
00169 }
00170 sleep( 2 );
00171 }
00172 else
00173 {
00174 int argc;
00175 char **argv;
00176 QString aux("");
00177
00178 argc = 0;
00179 argv = (char **)malloc(sizeof( char * )* (browserCmdLine->count() + 1));
00180 CreateFakeSlide();
00181 url += TempDirectory + "/init.html";
00182
00183 for( QStringList::Iterator it = browserCmdLine->begin(); it != browserCmdLine->end(); it++ )
00184 {
00185 (*it).replace( "%u", QString( (const char *)url ) );
00186 argv[ argc++ ] = strdup( (*it).latin1() );
00187 aux += " " + (*it);
00188 }
00189 argv[ argc++ ] = NULL;
00190
00191
00192 if( execvp( argv[ 0 ], argv ) == -1 )
00193 {
00194 RioErr << "execlp(): Failed to execute browser command:" << endl;
00195 RioErr << " " << aux.latin1() << endl;
00196 return;
00197 }
00198 }
00199 }
00200
00201 int CRioMMBrowser::OpenNetscapeWindow( void )
00202 {
00203 int status;
00204
00205 status = 0;
00206 if( !NetscapeWindow )
00207 {
00208 if( !(NetscapeWindow = mozilla_remote_find_window()) )
00209 StartBrowser();
00210 }
00211 else
00212 {
00213 if( !mozilla_remote_check_window() )
00214 StartBrowser();
00215 }
00216
00217 if( (NetscapeWindow = mozilla_remote_find_window()) )
00218 status = 1;
00219
00220 return( status );
00221 }
00222
00223 void CRioMMBrowser::SendCommandToNetscape( const char *command )
00224 {
00225 int status;
00226
00227 XSelectInput( dpy, NetscapeWindow, (PropertyChangeMask|StructureNotifyMask) );
00228
00229 mozilla_remote_obtain_lock();
00230
00231 status = mozilla_remote_command( false, command );
00232
00233 if( status != 6 )
00234 mozilla_remote_free_lock();
00235 }
00236
00237
00238
00239
00240
00241
00242
00243 int CRioMMBrowser::ProcessSignal( int sig, void *data )
00244 {
00245 int status;
00246
00247 status = 0;
00248 switch( sig )
00249 {
00250 case SIGHUP:
00251 readSettings();
00252 break;
00253
00254 case SIGCHLD:
00255 if( (long)data == browser_pid )
00256 dpy = 0x0;
00257 break;
00258 }
00259
00260
00261 if( status != 2 )
00262 CRioMMObject::ProcessSignal( sig, data );
00263
00264 return( status );
00265 }
00266
00267
00268
00269
00270
00271
00272
00273 void CRioMMBrowser::writeDefaultSettings()
00274 {
00275 ConfigData config;
00276 QStringList args;
00277 config.writeDefaultRioMMBrowserSettings();
00278 config.readRioMMClientSettings();
00279
00280 browserCmdLine = new QStringList( DEFAULT_BROWSER );
00281 args = QStringList::split( " ", config.getRioMMBArguments() );
00282 *browserCmdLine += args;
00283 }
00284
00285
00286
00287
00288
00289
00290 bool CRioMMBrowser::readSettings()
00291 {
00292 ConfigData config;
00293 bool ok1 = false,
00294 ok2 = false;
00295 QString browserPath, opt_value, temp;
00296 QStringList args;
00297
00298 config.readRioMMClientSettings();
00299 opt_value = config.getRioMMBVersion();
00300 if( opt_value != QString::null )
00301 {
00302
00303
00304
00305 if( opt_value == RIORC_RIOMMBROWSER_VERSION )
00306 {
00307 ok1 = true;
00308
00309 opt_value = QString::null;
00310 opt_value = config.getRioMMBBrowser();
00311
00312 if( opt_value != QString::null )
00313 {
00314 ok2 = true;
00315 if( browserCmdLine )
00316 delete browserCmdLine;
00317 browserCmdLine = new QStringList();
00318 browserCmdLine->append( config.getRioMMBBinary() );
00319 args = QStringList::split( " ", config.getRioMMBArguments() );
00320 *browserCmdLine += args;
00321
00322 }
00323 }
00324 }
00325
00326 return( ok1 && ok2 );
00327 }
00328
00329 int CRioMMBrowser::isMozillaWindow( Display *dpy, Window w )
00330 {
00331 int status;
00332 XTextProperty titleName;
00333
00334 status = 0;
00335 if( XGetWMName( dpy, w, &titleName ) != 0 )
00336 {
00337 if( titleName.encoding == XA_STRING )
00338 {
00339 const char *t_dir = (const char *)TempDirectory;
00340 if( strncmp( t_dir, (char *)titleName.value, strlen(t_dir) ) == 0 )
00341 status = 1;
00342 }
00343 }
00344
00345 return( status );
00346 }
00347
00348 Window CRioMMBrowser::mozilla_remote_find_window( void )
00349 {
00350 int i;
00351 unsigned int nkids;
00352 Window rw;
00353 Window root;
00354 Window parent;
00355 Window *kids;
00356 Window curWindow;
00357
00358 i = -1;
00359 curWindow = 0;
00360
00361 if( dpy == 0 )
00362 return 0;
00363
00364 rw = RootWindowOfScreen( DefaultScreenOfDisplay( dpy ) );
00365
00366 if( XQueryTree( dpy, rw, &root, &parent, &kids, &nkids ) )
00367 {
00368 if( nkids > 0 && kids != NULL )
00369 {
00370
00371 for( i = nkids - 1; i >= 0; i-- )
00372 {
00373
00374 curWindow = XmuClientWindow( dpy, kids[ i ] );
00375 if( isMozillaWindow( dpy, curWindow ) )
00376 break;
00377 }
00378 }
00379 XFree( kids );
00380 }
00381
00382 if( i < 0 )
00383 curWindow = 0;
00384
00385 return( curWindow );
00386 }
00387
00388 bool CRioMMBrowser::mozilla_remote_check_window()
00389 {
00390 Atom type;
00391 int format;
00392 bool retCode;
00393 unsigned long nitems, bytesafter;
00394 unsigned char *version = 0;
00395 int status = XGetWindowProperty( dpy, NetscapeWindow, XA_MOZILLA_VERSION,
00396 0, (65536 / sizeof( int )),
00397 False, XA_STRING,
00398 &type, &format, &nitems, &bytesafter,
00399 &version );
00400
00401 retCode = false;
00402 if(status != Success || !version)
00403 {
00404 #ifdef RIO_DEBUG2
00405 RioErr << "RioNetscape: window " << showbase << hex
00406 << (unsigned int) NetscapeWindow << noshowbase << dec
00407 << " is not a Netscape window." << endl;
00408 #endif
00409 }
00410 else
00411 {
00412 retCode = true;
00413 }
00414 XFree( version );
00415
00416 return( retCode );
00417 }
00418
00419
00420
00421 int CRioMMBrowser::mozilla_remote_command( bool raise_p, const char *command )
00422 {
00423 int result;
00424 Bool done = False;
00425 char new_command[ 255 ];
00426
00427 result = False;
00428
00429
00430
00431 if( !raise_p )
00432 {
00433 char *close;
00434 strcpy (new_command, command);
00435 close = strrchr (new_command, ')');
00436 if( close )
00437 strcpy (close, ", noraise)");
00438 else
00439 strcat (new_command, "(noraise)");
00440 command = new_command;
00441 }
00442
00443 XChangeProperty( dpy, NetscapeWindow, XA_MOZILLA_COMMAND, XA_STRING, 8,
00444 PropModeReplace, (unsigned char *)command,
00445 strlen( command ) );
00446
00447 while( !done )
00448 {
00449 XEvent event;
00450 XNextEvent( dpy, &event );
00451 if( event.xany.type == DestroyNotify &&
00452 event.xdestroywindow.window == NetscapeWindow )
00453 {
00454
00455 #ifdef RIO_DEBUG2
00456 RioErr << "RioNetscape: window " << showbase << hex
00457 << (unsigned int) NetscapeWindow << noshowbase << dec
00458 << " was destroyed." << endl;
00459 #endif
00460
00461 result = 6;
00462 goto DONE;
00463 }
00464 else if( event.xany.type == PropertyNotify &&
00465 event.xproperty.state == PropertyNewValue &&
00466 event.xproperty.window == NetscapeWindow &&
00467 event.xproperty.atom == XA_MOZILLA_RESPONSE )
00468 {
00469 Atom actual_type;
00470 int actual_format;
00471 unsigned long nitems, bytes_after;
00472 unsigned char *data = 0;
00473
00474 result = XGetWindowProperty( dpy, NetscapeWindow,
00475 XA_MOZILLA_RESPONSE,
00476 0, (65536 / sizeof (int)),
00477 True,
00478 XA_STRING,
00479 &actual_type, &actual_format,
00480 &nitems, &bytes_after,
00481 &data );
00482
00483 #ifdef RIO_DEBUG2
00484 if( result == Success && data && *data )
00485 {
00486 RioErr << "RioNetscape: (server sent " << MOZILLA_RESPONSE_PROP
00487 << " \"" << data << "\" to " << showbase << hex
00488 << (unsigned int) NetscapeWindow << noshowbase << dec
00489 << ".)" << endl;
00490
00491 }
00492 #endif
00493
00494 if(result != Success)
00495 {
00496 #ifdef RIO_DEBUG2
00497 RioErr << "RioNetscape: failed reading "
00498 << MOZILLA_RESPONSE_PROP << " from window " << showbase
00499 << hex << (unsigned int) NetscapeWindow << noshowbase
00500 << dec << "." << endl;
00501 #endif
00502
00503 result = 6;
00504 done = True;
00505 }
00506 else if(!data || strlen((char *) data) < 5)
00507 {
00508 #ifdef RIO_DEBUG2
00509 RioErr << "RioNetscape: invalid data on "
00510 << MOZILLA_RESPONSE_PROP << " property of window "
00511 << showbase << hex << (unsigned int) NetscapeWindow
00512 << noshowbase << dec << "." << endl;
00513 #endif
00514
00515 result = 6;
00516 done = True;
00517 }
00518 else if(*data == '1')
00519 {
00520 #ifdef RIO_DEBUG2
00521 RioErr << "RioNetscape: " << data + 4 << endl;
00522 #endif
00523
00524
00525 done = False;
00526 }
00527 else if( !strncmp( (char *)data, "200", 3 ) )
00528 {
00529 result = 0;
00530 done = True;
00531 }
00532 else if( *data == '2' )
00533 {
00534 #ifdef RIO_DEBUG2
00535 RioErr << "RioNetscape: " << data + 4 << endl;
00536 #endif
00537
00538 result = 0;
00539 done = True;
00540 }
00541 else if( *data == '3' )
00542 {
00543 #ifdef RIO_DEBUG2
00544 RioErr << "RioNetscape: internal error: server wants more "
00545 << "information? (" << data << ")" << endl;
00546 #endif
00547
00548 result = 3;
00549 done = True;
00550 }
00551 else if( *data == '4' ||
00552 *data == '5')
00553 {
00554 result = (*data - '0');
00555 done = True;
00556 }
00557 else
00558 {
00559 #ifdef RIO_DEBUG2
00560 RioErr << "RioNetscape: unrecognised "
00561 << MOZILLA_RESPONSE_PROP << " from window " << showbase
00562 << hex << (unsigned int) NetscapeWindow << noshowbase
00563 << dec << ": " << data << endl;
00564 #endif
00565
00566 result = 6;
00567 done = True;
00568 }
00569
00570 if( data )
00571 XFree( data );
00572 }
00573 #ifdef DEBUG_PROPS
00574 else if( event.xany.type == PropertyNotify &&
00575 event.xproperty.window == window &&
00576 event.xproperty.state == PropertyDelete &&
00577 event.xproperty.atom == XA_MOZILLA_COMMAND)
00578 {
00579 RioErr << "RioNetscape: (server " << showbase << hex
00580 << (unsigned int) NetscapeWindow << noshowbase << dec
00581 << " has accepted " << MOZILLA_RESPONSE_PROP << ".)"
00582 << endl;
00583 }
00584 #endif
00585 }
00586
00587 DONE:
00588
00589 return result;
00590 }
00591
00592 void CRioMMBrowser::mozilla_remote_obtain_lock()
00593 {
00594 bool locked = false;
00595 bool waited = false;
00596
00597 if( !lock_data )
00598 {
00599 lock_data = (char *) malloc(255);
00600 sprintf( lock_data, "pid%d@", getpid() );
00601 if( gethostname( lock_data + strlen( lock_data ), 100) )
00602 {
00603 Rioperror("gethostname");
00604 exit (-1);
00605 }
00606 }
00607
00608 do
00609 {
00610 int result;
00611 Atom actual_type;
00612 int actual_format;
00613 unsigned long nitems, bytes_after;
00614 unsigned char *data = 0;
00615
00616 XGrabServer( dpy );
00617
00618 result = XGetWindowProperty( dpy, NetscapeWindow, XA_MOZILLA_LOCK,
00619 0, (65536 / sizeof( int )),
00620 False,
00621 XA_STRING,
00622 &actual_type, &actual_format,
00623 &nitems, &bytes_after,
00624 &data );
00625 if( result != Success || actual_type == None )
00626 {
00627
00628 XChangeProperty( dpy, NetscapeWindow, XA_MOZILLA_LOCK, XA_STRING,
00629 8, PropModeReplace, (unsigned char *) lock_data,
00630 strlen( lock_data ) );
00631 locked = true;
00632 }
00633
00634 XUngrabServer( dpy );
00635 XSync( dpy, 0 );
00636
00637 if( !locked )
00638 {
00639
00640
00641
00642
00643 #ifdef RIO_DEBUG2
00644 RioErr << ": window " << showbase << hex
00645 << (unsigned int) NetscapeWindow << noshowbase << dec
00646 << " is locked by " << data << "; waiting..." << endl;
00647 #endif
00648
00649 waited = true;
00650
00651 while( 1 )
00652 {
00653 XEvent event;
00654 XNextEvent( dpy, &event );
00655 if( event.xany.type == DestroyNotify &&
00656 event.xdestroywindow.window == NetscapeWindow )
00657 {
00658 RioErr << ": window " << showbase << hex
00659 << (unsigned int) NetscapeWindow << noshowbase << dec
00660 << " unexpectedly destroyed." << endl;
00661 exit (6);
00662 }
00663 else if( event.xany.type == PropertyNotify &&
00664 event.xproperty.state == PropertyDelete &&
00665 event.xproperty.window == NetscapeWindow &&
00666 event.xproperty.atom == XA_MOZILLA_LOCK )
00667 {
00668
00669
00670 #ifdef DEBUG_PROPS
00671 RioErr << ": (" << showbase << hex
00672 << (unsigned int) NetscapeWindow << noshowbase << dec
00673 << " unlocked, trying again...)" << endl;
00674 #endif
00675
00676 break;
00677 }
00678 }
00679 }
00680
00681 if( data )
00682 XFree( data );
00683 }
00684
00685
00686 while(!locked );
00687
00688 if( waited )
00689 RioErr << ": obtained lock." << endl;
00690 }
00691
00692
00693 void CRioMMBrowser::mozilla_remote_free_lock()
00694 {
00695 int result;
00696 Atom actual_type;
00697 int actual_format;
00698 unsigned long nitems, bytes_after;
00699 unsigned char *data = 0;
00700
00701 result = XGetWindowProperty( dpy, NetscapeWindow, XA_MOZILLA_LOCK,
00702 0, (65536 / sizeof (int)),
00703 True,
00704 XA_STRING,
00705 &actual_type, &actual_format,
00706 &nitems, &bytes_after,
00707 &data );
00708 if( result != Success )
00709 {
00710 #ifdef RIO_DEBUG2
00711 RioErr << ": unable to read and delete " << MOZILLA_LOCK_PROP
00712 << " property" << endl;
00713 #endif
00714
00715 return;
00716 }
00717 else if( !data || !*data )
00718 {
00719 #ifdef RIO_DEBUG2
00720 RioErr << ": invalid data on " << MOZILLA_LOCK_PROP << " of window "
00721 << showbase << hex << (unsigned int) NetscapeWindow
00722 << noshowbase << dec << "." << endl;
00723 #endif
00724
00725 return;
00726 }
00727 else if( strcmp( (char *) data, lock_data) )
00728 {
00729 #ifdef RIO_DEBUG2
00730 RioErr << ": " << MOZILLA_LOCK_PROP << " was stolen! Expected \""
00731 << lock_data << "\", saw \"" << data << "\"!" << endl;
00732 #endif
00733
00734 return;
00735 }
00736
00737 if( data )
00738 XFree( data );
00739 }