/*************************************************************************** * Copyright 2004 Lubos Lunak * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * * * ***************************************************************************/ #include #include #include #include #ifdef HAVE_XINERAMA extern "C" { // for older XFree86 versions #include } #endif #include #include #include # ifdef HAVE_SYS_TIME_H # include # endif #include //#define DEBUG int main( int argc, char* argv[]) { bool small = false; bool test = false; bool print_pid = false; for( int i = 1; i < argc; ++i ) { if( strcmp( argv[ i ], "--test" ) == 0 ) test = true; if( strcmp( argv[ i ], "--pid" ) == 0 ) print_pid = true; if( strcmp( argv[ i ], "SimpleSmall" ) == 0 ) small = true; } pid_t pid = fork(); if( pid < -1 ) { perror( "fork()" ); return -1; } if( pid != 0 ) { // parent if( print_pid ) printf( "%d\n", pid ); return 0; } // child close( 0 ); // close stdin,stdout,stderr, otherwise startkde will block close( 1 ); close( 2 ); Display* dpy = XOpenDisplay( NULL ); if( dpy == NULL ) return 1; int sx, sy, sw, sh; Window* wins = NULL; int wins_count = 0; #ifdef HAVE_XINERAMA // Xinerama code from Qt XineramaScreenInfo *xinerama_screeninfo = 0; int unused; bool use_xinerama = XineramaQueryExtension( dpy, &unused, &unused ) && XineramaIsActive( dpy ); if (use_xinerama) { int screenCount; xinerama_screeninfo = XineramaQueryScreens( dpy, &screenCount ); sx = xinerama_screeninfo[ 0 ].x_org; sy = xinerama_screeninfo[ 0 ].y_org; sw = xinerama_screeninfo[ 0 ].width; sh = xinerama_screeninfo[ 0 ].height; if( !small ) { // create windows covering other xinerama screens wins_count = screenCount; wins = new Window[ wins_count ]; for( int i = 1; // not 0 i < wins_count; ++i ) { XSetWindowAttributes attrs; attrs.override_redirect = True; attrs.background_pixel = BlackPixel( dpy, 0 ); // background wins[ i ] = XCreateWindow( dpy, DefaultRootWindow( dpy ), xinerama_screeninfo[ i ].x_org, xinerama_screeninfo[ i ].y_org, xinerama_screeninfo[ i ].width, xinerama_screeninfo[ i ].height, 0, CopyFromParent, CopyFromParent, CopyFromParent, CWOverrideRedirect | CWBackPixel, &attrs ); } } } else #endif { sx = sy = 0; sw = WidthOfScreen( ScreenOfDisplay( dpy, DefaultScreen( dpy ))); sh = HeightOfScreen( ScreenOfDisplay( dpy, DefaultScreen( dpy ))); } XSetWindowAttributes attrs; attrs.override_redirect = True; const int states = 6; const int frame = 3; const int segment = sw / 2 / states; const int pw = segment * states + 2 * frame; // size of progressbar const int ph = sh / 20 + frame; const int px = small ? 0 : sx + ( sw - pw ) / 2; // position in the pixmap const int py = small ? 0 : sy + ( sh - ph ) / 2; const int x = small ? sx + ( sw - pw ) / 2 : sx; // position of the window const int y = small ? sy + ( sh - ph ) / 2 : sy; const int w = small ? pw : sw; const int h = small ? ph : sh; if( wins == NULL ) { wins = new Window[ 1 ]; wins_count = 1; } Window win = XCreateWindow( dpy, DefaultRootWindow( dpy ), x, y, w, h, 0, CopyFromParent, CopyFromParent, CopyFromParent, CWOverrideRedirect, &attrs ); wins[ 0 ] = win; Pixmap pix = XCreatePixmap( dpy, DefaultRootWindow( dpy ), w, h, DefaultDepth( dpy, 0 )); XGCValues values; values.foreground = BlackPixel( dpy, 0 ); // background GC gc = XCreateGC( dpy, pix, GCForeground, &values ); XFillRectangle( dpy, pix, gc, 0, 0, w, h ); values.foreground = WhitePixel( dpy, 0 ); // outline XChangeGC( dpy, gc, GCForeground, &values ); XFillRectangle( dpy, pix, gc, px, py, pw, ph ); values.foreground = BlackPixel( dpy, 0 ); // progressbar XChangeGC( dpy, gc, GCForeground, &values ); XSetWindowBackgroundPixmap( dpy, win, pix ); XSelectInput( dpy, DefaultRootWindow( dpy ), SubstructureNotifyMask ); for( int i = 0; i < wins_count; ++i ) { XSelectInput( dpy, wins[ i ], ButtonPressMask ); XClassHint class_hint; class_hint.res_name = const_cast< char* >( "ksplashsimple" ); class_hint.res_class = const_cast< char* >( "ksplashsimple" ); XSetWMProperties( dpy, wins[ i ], NULL, NULL, NULL, 0, NULL, NULL, &class_hint ); XMapWindow( dpy, wins[ i ] ); } int pos = 0; int state = 1; // cannot check dcop connection - make this state initial const int delay = 200; // ms const int doubleclick_delay = 200; // mouse doubleclick delay - in ms time_t final_time = time( NULL ) + 300; time_t test_time = time( NULL ) + 1; struct timeval button_press_time, current_time; // we need timeval to deal with milliseconds button_press_time.tv_sec = 0; button_press_time.tv_usec = 0; long click_delay, click_delay_seconds, click_delay_useconds; Atom kde_splash_progress = XInternAtom( dpy, "_KDE_SPLASH_PROGRESS", False ); for(;;) { while( XPending( dpy )) { XEvent ev; XNextEvent( dpy, &ev ); if( ev.type == ButtonPress && ev.xbutton.button == Button1 ) { gettimeofday( ¤t_time, NULL ); // find difference in milliseconds with current and previous mouse presses times click_delay_seconds = current_time.tv_sec - button_press_time.tv_sec; click_delay_useconds = current_time.tv_usec - button_press_time.tv_usec; click_delay = ( click_delay_seconds * 1000 + click_delay_useconds / 1000.0 ) + 0.5; if( click_delay <= doubleclick_delay ) { // close splash on doubleclick final_time = time( NULL ); break; } gettimeofday( &button_press_time, NULL ); } if( ev.type == ConfigureNotify && ev.xconfigure.event == DefaultRootWindow( dpy )) { XRaiseWindow( dpy, wins[ 0 ] ); if( wins_count > 1 ) XRestackWindows( dpy, wins, wins_count ); } if( ev.type == ClientMessage && ev.xclient.window == DefaultRootWindow( dpy ) && ev.xclient.message_type == kde_splash_progress ) { // these are also in ksplashx and in krunner const char* s = ev.xclient.data.b; #ifdef DEBUG fprintf( stderr,"MESSAGE: %s\n", s ); #endif if( strcmp( s, "initial" ) == 0 && state < 0 ) state = 0; // not actually used else if( strcmp( s, "kded" ) == 0 && state < 1 ) state = 1; else if( strcmp( s, "confupdate" ) == 0 && state < 2 ) state = 2; else if( strcmp( s, "kcminit" ) == 0 && state < 3 ) state = 3; else if( strcmp( s, "ksmserver" ) == 0 && state < 4 ) state = 4; else if( strcmp( s, "wm" ) == 0 && state < 5 ) state = 5; else if( strcmp( s, "desktop" ) == 0 && state < 6 ) state = 6; // This last one isn't used, make splash go away as soon as desktop is ready. // else if( strcmp( s, "ready" ) == 0 && state < 7 ) // state = 7; } } if( test && time( NULL ) >= test_time ) { ++state; test_time = time( NULL ) + 1; } if( pos != state ) { while( pos < state && pos < states ) { #ifdef DEBUG fprintf( stderr, "POS: %d\n", pos ); #endif XFillRectangle( dpy, pix, gc, px + frame + pos * segment, py + frame, segment, ph - 2 * frame ); XSetWindowBackgroundPixmap( dpy, win, pix ); XClearWindow( dpy, win ); ++pos; if( pos >= states ) { #ifdef DEBUG fprintf( stderr, "CLOSING DOWN\n" ); #endif final_time = time( NULL ) + 2; } } } fd_set set; FD_ZERO( &set ); FD_SET( XConnectionNumber( dpy ), &set ); struct timeval tv; tv.tv_sec = 0; tv.tv_usec = delay * 1000; select( XConnectionNumber( dpy ) + 1, &set, NULL, NULL, &tv ); if( time( NULL ) >= final_time ) { #ifdef DEBUG fprintf( stderr, "EXITING\n" ); #endif break; // ---> } } XFreePixmap( dpy, pix ); for( int i = 0; i < wins_count; ++i ) XDestroyWindow( dpy, wins[ i ] ); delete[] wins; XFreeGC( dpy, gc ); XCloseDisplay( dpy ); }