2
* italc.cpp - main-file for iTALC-Application
5
* Copyright (c) 2004-2005 Tobias Doerffel <tobias@doerffel.de>
7
* This program is free software; you can redistribute it and/or
8
* modify it under the terms of the GNU General Public
9
* License as published by the Free Software Foundation; either
10
* version 2 of the License, or (at your option) any later version.
12
* This program is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
* General Public License for more details.
17
* You should have received a copy of the GNU General Public
18
* License along with this program (see COPYING); if not, write to the
19
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20
* Boston, MA 02111-1307, USA.
28
#include <qapplication.h>
29
#include <qtranslator.h>
30
#include <qtextcodec.h>
32
#if QT_VERSION >= 0x030200
33
#include <qsplashscreen.h>
35
#include <qmessagebox.h>
39
#include <qpopupmenu.h>
40
#include <qsplitter.h>
41
#include <qtoolbutton.h>
43
#include <qworkspace.h>
45
#include <qdatetime.h>
48
#include "client_manager.h"
49
#include "about_dialog.h"
53
#include "italc_side_bar.h"
54
#include "overview_widget.h"
55
#include "user_list.h"
56
#include "chat_management.h"
57
#include "screenshot_list.h"
58
#include "config_widget.h"
59
#include "help_widget.h"
60
#include "system_environment.h"
61
#include "italc_rfb_ext.h"
62
#include "rfb_connection.h"
66
#include "italc_side_bar.moc"
69
#if QT_VERSION >= 0x030200
70
QSplashScreen * splashScreen = NULL;
76
void interrupted( int sig )
78
fprintf (stderr, "Got signal %d. Ignoring.\n", sig);
83
// good old main-function... initializes qt-app and starts iTALC
84
int main (int argc, char * * argv) {
86
//signal (SIGBUS, interrupted);
87
//signal (SIGSEGV, interrupted);
88
//signal (SIGFPE, interrupted);
91
QApplication app( argc, argv );
92
#if QT_VERSION >= 0x030200
93
// set work-directory to
94
//QDir::setCurrent( app.applicationDirPath() );
95
QPixmap splash = embed::getIconPixmap( "splash" );
96
QPixmap actual_splash = QPixmap::grabWindow( QApplication::desktop()->winId(),
97
( QApplication::desktop()->availableGeometry().width()-splash.width() ) / 2,
98
( QApplication::desktop()->availableGeometry().height()-splash.height() ) / 2,
99
splash.width(), splash.height() );
100
//bitBlt( &actual_splash, 0, 0, &splash, 0, 0, splash.width(), splash.height(), Qt::XorROP );
101
splashScreen = new QSplashScreen( actual_splash );
102
splashScreen->setMask( splash.createHeuristicMask() );
103
splashScreen->show();
105
// ok, let's have a nice fade-in-effect ;-)
106
QImage splash_img = splash.convertToImage();
107
QImage actual_splash_img = actual_splash.convertToImage();
108
QImage dest_img = actual_splash.convertToImage();
111
while( t.elapsed() < 2000 && splashScreen->isShown() )
113
short int i = 256*t.elapsed()/1500;
119
memcpy( dest_img.bits(), actual_splash_img.bits(), actual_splash_img.width()*actual_splash_img.height() * 4 );
120
register uchar * rs = splash_img.bits();
121
register uchar * gs = rs + 1;
122
register uchar * bs = gs + 1;
123
register uchar * as = bs + 1;
124
register uchar * rd = dest_img.bits();
125
register uchar * gd = rd + 1;
126
register uchar * bd = gd + 1;
127
for( short int y = 0; y < dest_img.height(); ++y )
129
for( short int x = 0; x < dest_img.width(); ++x )
131
short int opac = static_cast<short int>( (i*(short int)*as)>>8 );
132
*rd += ( ( ( *rs - *rd ) * opac ) >> 8 );
134
*gd += ( ( ( *gs - *gd ) * opac ) >> 8 );
136
*bd += ( ( ( *bs - *bd ) * opac ) >> 8 );
141
// conversion is slow as hell if desktop-depth != 24bpp...
142
actual_splash.convertFromImage( dest_img );
143
splashScreen->setPixmap( actual_splash );
148
QString loc = QString( QTextCodec::locale() ).section( '_', 0, 0 );
149
// load translation for Qt-widgets/-dialogs
150
embed::loadTranslation( QString( "qt_" ) + loc );
151
// load actual translation for iTALC
152
embed::loadTranslation( loc );
154
// read private key, create it if it doesn't exist yet
155
rfbConnection::initializeAuthentication();
157
// now create the main-window
158
italc * italc_main_window = italc::inst();
159
#if QT_VERSION >= 0x030200
160
// hide splash-screen as soon as main-window is shown
161
splashScreen->finish( italc_main_window );
163
app.setMainWidget( italc_main_window );
164
italc_main_window->show();
167
return( app.exec() );
174
italc * italc::s_instOfMe = NULL;
176
bool italc::ensureConfigPathExists( void )
178
QDir home = QDir::home();
179
// does a file/dir named ITALC_CONFIG_PATH exist?
180
if( home.exists( ITALC_CONFIG_PATH ) == FALSE )
182
// no, then create dir
183
return( home.mkdir( ITALC_CONFIG_PATH ) );
185
// exists, so test, whether it is a file
186
else if( home.cd( ITALC_CONFIG_PATH ) == FALSE )
188
// it is, so we remove it
189
if( home.remove( ITALC_CONFIG_PATH ) == FALSE )
191
// remove failed, we give up
194
return( home.mkdir( ITALC_CONFIG_PATH ) );
203
QMainWindow( 0, "", WDestructiveClose ),
204
m_openedTabInSideBar( 1 )
208
setCaption( tr( "iTALC" ) + " " + VER_STRING );
209
setIcon( embed::getIconPixmap( "splash" ) );
210
setUsesBigPixmaps( TRUE );
213
QHBox * hbox = new QHBox( this );
216
m_sideBar = new italcSideBar( italcSideBar::Vertical, hbox );
217
m_sideBar->setStyle( italcSideBar::VSNET/*KDEV3ICON*/ );
220
// create splitter, which is used for splitting sidebar-workspaces from main-workspace
221
m_splitter = new QSplitter( Qt::Horizontal, hbox );
222
#if QT_VERSION >= 0x030200
223
m_splitter->setChildrenCollapsible( FALSE );
226
// create actual workspace for client-windows
227
m_workspace = new QWorkspace( m_splitter );
228
m_workspace->setScrollBarsEnabled( TRUE );
229
m_workspace->setPaletteBackgroundPixmap( embed::getIconPixmap( "background_artwork" ) );
232
// create instance of clientManager -> loads all available classrooms and clients from config-files
233
clientManager * cm = clientManager::inst();
234
// now create all sidebar-workspaces
235
m_overviewWidget = new overviewWidget( m_splitter );
236
m_userList = new userList( m_splitter );
237
m_chatManagement = new chatManagement( m_splitter );
238
m_screenshotList = new screenshotList( m_splitter );
239
m_configWidget = new configWidget( m_splitter );
240
m_helpWidget = new helpWidget( m_splitter );
242
// append sidebar-workspaces to sidebar
244
m_sideBar->appendTab( m_overviewWidget, ++id );
245
m_sideBar->appendTab( cm, ++id );
246
m_sideBar->appendTab( m_userList, ++id );
247
m_sideBar->appendTab( m_chatManagement, ++id );
248
m_sideBar->appendTab( m_screenshotList, ++id );
249
m_sideBar->appendTab( m_configWidget, ++id );
250
m_sideBar->appendTab( m_helpWidget, ++id );
251
m_sideBar->setPosition( italcSideBar::Left );
252
m_sideBar->setTab( m_openedTabInSideBar, TRUE );
254
m_splitter->moveToLast( m_workspace );
256
setCentralWidget( hbox );
260
m_filePopupMenu = new QPopupMenu( this );
261
menuBar()->insertItem( tr( "&File" ), m_filePopupMenu );
263
m_filePopupMenu->insertItem( embed::getIconPixmap( "exit" ), tr( "&Quit" ), qApp, SLOT( closeAllWindows() ), CTRL+Key_Q );
267
// clients-popup-menu
268
m_actionsPopupMenu = new QPopupMenu( this );
269
menuBar()->insertItem( tr( "&Actions" ), m_actionsPopupMenu );
271
m_actionsPopupMenu->insertItem( embed::getIconPixmap( "client_start_fullscreen_demo" ), tr( "Start fullscreen-demo" ), cm,
272
SLOT( startFullScreenDemo() ) );
273
m_actionsPopupMenu->insertItem( embed::getIconPixmap( "client_start_demo" ), tr( "Start window-demo" ), cm, SLOT( startDemo() ) );
274
m_actionsPopupMenu->insertItem( embed::getIconPixmap( "client_stop_demo" ), tr( "Stop demo" ), cm, SLOT( stopDemo() ) );
275
m_actionsPopupMenu->insertItem( embed::getIconPixmap( "client_msg" ), tr( "Send message to all clients" ), cm,
276
SLOT( sendMessage() ) );
277
m_actionsPopupMenu->insertItem( embed::getIconPixmap( "distribute_file" ), tr( "Distribute file" ), cm, SLOT( distributeFile() ) );
278
m_actionsPopupMenu->insertItem( embed::getIconPixmap( "collect_files" ), tr( "Collect files" ), cm, SLOT( collectFiles() ) );
279
m_actionsPopupMenu->insertItem( embed::getIconPixmap( "client_lock_x" ), tr( "Lock screens" ), cm, SLOT( lockScreens() ) );
280
m_actionsPopupMenu->insertItem( embed::getIconPixmap( "client_unlock_x" ), tr( "Unlock screens" ), cm, SLOT( unlockScreens() ) );
281
//m_actionsPopupMenu->insertItem( embed::getIconPixmap( "client_restart_x" ), tr( "Restart X on all clients" ), cm, SLOT( restartX() ) );
283
m_actionsPopupMenu->insertSeparator();
285
m_actionsPopupMenu->insertItem( embed::getIconPixmap( "client_kill_games" ), tr( "Kill games on all clients" ), cm,
286
SLOT( killGames() ) );
287
m_actionsPopupMenu->insertItem( embed::getIconPixmap( "client_kill_browsers" ), tr( "Kill browsers on all clients" ), cm,
288
SLOT( killBrowsers() ) );
290
m_actionsPopupMenu->insertSeparator();
292
m_actionsPopupMenu->insertItem( embed::getIconPixmap( "client_power_on" ), tr( "Power on all clients" ), cm,
293
SLOT( powerOnClients() ) );
294
m_actionsPopupMenu->insertItem( embed::getIconPixmap( "client_reboot" ), tr( "Reboot all clients" ), cm,
295
SLOT( rebootClients() ) );
296
//m_actionsPopupMenu->insertSeparator ();
297
m_actionsPopupMenu->insertItem (embed::getIconPixmap( "client_power_off" ), tr( "Power off all clients" ),
298
cm, SLOT( powerOffClients() ) );
299
m_actionsPopupMenu->insertItem (embed::getIconPixmap( "client_exec_cmds" ), tr( "Execute commands on all clients" ),
300
cm, SLOT( execCmds() ) );
304
m_actionsPopupMenu->insertSeparator();
306
QPopupMenu * single_clients_submenu = new QPopupMenu( m_actionsPopupMenu );
307
clientManager::inst()->createActionMenu( single_clients_submenu );
309
m_actionsPopupMenu->insertItem( embed::getIconPixmap( "client" ), tr( "Action on single client" ), single_clients_submenu );
311
QPopupMenu * classrooms_submenu = new QPopupMenu( m_actionsPopupMenu );
312
clientManager::inst()->createActionMenuForClassRooms( classrooms_submenu );
314
m_actionsPopupMenu->insertItem( embed::getIconPixmap( "classroom_opened" ), tr( "Action for whole classroom" ),
315
classrooms_submenu );
320
m_helpPopupMenu = new QPopupMenu( this );
321
menuBar()->insertItem( tr( "&Help" ), m_helpPopupMenu );
323
m_helpPopupMenu->insertItem( embed::getIconPixmap( "whatsthis" ), tr( "What's this?" ), this, SLOT( enterWhatsThisMode() ) );
324
m_helpPopupMenu->insertSeparator();
325
m_helpPopupMenu->insertItem( embed::getIconPixmap( "info" ), tr( "About iTALC" ), this, SLOT( aboutITALC() ) );
328
// create the action-toolbar
329
m_actionToolBar = new QToolBar( this );
330
addDockWindow( m_actionToolBar, tr( "Actions" ), DockTop, TRUE );
332
QToolButton * sfd = new QToolButton( embed::getIconPixmap( "client_start_fullscreen_demo" ), tr( "Start fullscreen-demo" ),
333
QString::null, cm, SLOT( startFullScreenDemo() ), m_actionToolBar );
334
QWhatsThis::add( sfd, tr( "With this button you can start a fullscreen-demo on all visible clients. While a fullscreen-demo is "
335
"running, the users neither are able to quit the demo nor can they do something else. This is "
336
"good if you want to have the user's full attention." ) );
338
QToolButton * swd = new QToolButton( embed::getIconPixmap( "client_start_demo" ), tr( "Start window-demo" ), QString::null, cm,
339
SLOT( startDemo() ), m_actionToolBar );
340
QWhatsThis::add( swd, tr( "With this button you can start a window-demo on all visible clients. The users are able to minimize or "
341
"resize the demo-window, so they can continue with their work. But at any time they can restore the "
342
"window, so that they can see, what you're showing to them." ) );
344
QToolButton * sd = new QToolButton( embed::getIconPixmap( "client_stop_demo" ), tr( "Stop demo" ), QString::null, cm,
345
SLOT( stopDemo() ), m_actionToolBar );
346
QWhatsThis::add( sd, tr( "Click on this button if you want to stop the demo. It doesn't matter what kind of demo (fullscreen/window) "
347
"you started. Either the screen is unlocked and the users can continue their work or the demo-window "
348
"ist just closed." ) );
350
QToolButton * sm = new QToolButton( embed::getIconPixmap( "client_msg" ), tr( "Send message to all clients" ), QString::null, cm,
351
SLOT( sendMessage() ), m_actionToolBar );
352
QWhatsThis::add( sm, tr( "To send a message to all users, you can use this button. After clicking on it, a window opens and you can "
353
"enter the text, which should be shown on every client. This is for example useful when giving new "
354
"tasks for every user." ) );
356
QToolButton * df = new QToolButton( embed::getIconPixmap( "distribute_file" ), tr( "Distribute a file to all clients" ),
357
QString::null, cm, SLOT( distributeFile() ), m_actionToolBar );
358
QWhatsThis::add( df, tr( "If you want to distribute a file to all clients, you can click on this button. You can select the file "
359
"you want to distribute and then this file is copied into every users home-directory." ) );
361
QToolButton * cf = new QToolButton( embed::getIconPixmap( "collect_files" ), tr( "Collect files from all clients" ), QString::null,
362
cm, SLOT( collectFiles() ), m_actionToolBar );
363
QWhatsThis::add( cf, tr( "For collecting a specific file from every user/client click on this button. Then you can enter the "
364
"filename (wildcards are possible) and the file is copied from each client if it exists." ) );
366
QToolButton * ls = new QToolButton( embed::getIconPixmap( "client_lock_x" ), tr( "Lock screens" ), QString::null, cm,
367
SLOT( lockScreens() ), m_actionToolBar);
368
QWhatsThis::add( ls, tr( "Often it's neccessary to have the user's full attention. To achieve this, click on this button and the "
369
"screen of every client is locked. The users can't do something, because their screens got black "
370
"and the computer doesn't react to any inputs (mouse, keyboard...)." ) );
372
QToolButton * uls = new QToolButton( embed::getIconPixmap( "client_unlock_x" ), tr( "Unlock screens" ), QString::null, cm,
373
SLOT( unlockScreens() ), m_actionToolBar );
374
QWhatsThis::add( uls, tr( "To unlock the client's screens, click on this button. Then all users will be able to continue their "
377
m_actionToolBar->addSeparator();
379
QToolButton * kg = new QToolButton( embed::getIconPixmap( "client_kill_games" ), tr( "Kill games on all clients" ), QString::null,
380
cm, SLOT( killGames() ), m_actionToolBar );
381
QWhatsThis::add( kg, tr( "Clicking this button will kill all typical Linux/KDE-Games. Especially when teaching young pupils this "
382
"is needed very often..." ) );
384
QToolButton * kb = new QToolButton( embed::getIconPixmap( "client_kill_browsers" ), tr( "Kill browsers on all clients" ),
385
QString::null, cm, SLOT( killBrowsers() ), m_actionToolBar );
386
QWhatsThis::add( kb, tr( "Clicking this button will kill all browser-windows. This can be used, if the use of the internet is not "
387
"allowed at the moment." ) );
389
m_actionToolBar->addSeparator();
391
QToolButton * pon = new QToolButton( embed::getIconPixmap( "client_power_on" ), tr( "Power on all clients" ), QString::null, cm,
392
SLOT( powerOnClients() ), m_actionToolBar );
393
QWhatsThis::add( pon, tr( "Click on this button if you want to power on all clients. For using this feature, the clients must have "
394
"Wake-on-LAN-capability. This function is very useful, because you don't have to power on each "
395
"computer by hand." ) );
397
QToolButton * rac = new QToolButton( embed::getIconPixmap( "client_reboot" ), tr( "Reboot all clients" ), QString::null, cm,
398
SLOT( rebootClients() ), m_actionToolBar );
399
QWhatsThis::add( rac, tr( "Sometimes it is neccessary to reboot all clients, for example if the configuration has changed. If users "
400
"are logged in on the machines to be rebooted, a confirmation will appear for every client." ) );
402
QToolButton * poff = new QToolButton( embed::getIconPixmap( "client_power_off" ), tr( "Power off all clients" ), QString::null, cm,
403
SLOT( powerOffClients() ), m_actionToolBar );
404
QWhatsThis::add( poff, tr( "If you want to power off all clients (for example at the end of a lesson) you can click on this "
408
// now create toolbar for view-settings
409
m_viewToolBar = new QToolBar( this );
410
addDockWindow( m_viewToolBar, tr( "View" ), DockTop, FALSE );
412
QToolButton * ocs = new QToolButton( embed::getIconPixmap( "optimize_client_size" ), tr( "Optimize client-size" ), QString::null,
413
cm, SLOT( optimizeClientSize() ), m_viewToolBar );
414
QWhatsThis::add( ocs, tr( "By clicking this button, the greates possible size for the client-windows is adjusted, so that you "
415
"don't have to scroll. Then as much as possible available space is used. The client-windows are "
418
QToolButton * ics = new QToolButton( embed::getIconPixmap( "inc_client_size" ), tr( "Increase client-size" ), QString::null, cm,
419
SLOT( increaseClientSize() ), m_viewToolBar );
420
QWhatsThis::add( ics, tr( "When you click on this button, the size of the visible client-windows is increased, if they have not "
421
"already the biggest possible size. The size is limited to protect privacy of the users." ) );
423
QToolButton * dcs = new QToolButton( embed::getIconPixmap( "dec_client_size" ), tr( "Decrease client-size" ), QString::null, cm,
424
SLOT( decreaseClientSize() ), m_viewToolBar );
425
QWhatsThis::add( dcs, tr( "When you click on this button, the size of the visible client-windows is decreased, if they have not "
426
"already the smallest possible size." ) );
428
m_viewToolBar->addSeparator();
430
QToolButton * swr = new QToolButton( embed::getIconPixmap( "classroom_switch" ), tr( "Switch classroom" ), QString::null,
431
NULL, NULL, m_viewToolBar );
432
swr->setPopup( clientManager::inst()->quickSwitchMenu() );
433
swr->setPopupDelay( 1 );
434
QWhatsThis::add( swr, tr( "Click on this button, to switch between classrooms." ) );
436
QString win_cfg = cm->winCfg();
437
QTextStream ts( &win_cfg, IO_ReadOnly );
440
// if there's still a demo-server running (for example after iTALC-crash...) quit it...
441
systemEnvironment::demoServer::stop();
442
// ...and start a new one
443
systemEnvironment::demoServer::start();
446
QTimer::singleShot( 1000, cm, SLOT( updateClients() ) );
449
// start client-update-thread with high priority. otherwise we could loose connections because of timeouts...
450
#if QT_VERSION >= 0x030200
451
start( QThread::HighPriority );
467
void italc::run( void )
471
// reload all clients...
473
QValueVector<client *> clients = clientManager::inst()->visibleClients();
475
// loop through all clients
476
for( Q_UINT16 cl = 0; cl < clients.size(); ++cl )
478
// reload current client
479
clients[cl]->processCmd( client::RELOAD, CONFIRM_NO );
482
m_userList->reload();
484
if( client::reloadScreenshotList() )
486
m_screenshotList->reloadList();
488
client::resetReloadOfScreenshotList();
490
// now sleep before reloading clients again
491
QThread::sleep( clientManager::inst()->updateInterval() );
493
// now do cleanup-work
494
clientManager::inst()->doCleanupWork();
501
void italc::closeEvent( QCloseEvent * _ce )
503
// TODO: add check whether screens are locked!
504
if( clientManager::inst()->demoRunning() )
506
QMessageBox::information( this, tr( "Demo running" ), tr( "You can't exit while a demo is running! Please stop the demo "
507
"on all clients and try again!" ), QMessageBox::Ok );
516
systemEnvironment::demoServer::stop();
518
clientManager::inst()->doCleanupWork();
527
void italc::aboutITALC( void )
529
aboutDialog( this ).exec();