/*************************************************************************** * Copyright (C) 2004-2006 by Danny Kukawka * * , * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of version 2 of the GNU General Public License * * as published by the Free Software Foundation. * * * * 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, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ /*! \file screen.cpp * All here displayed file members of screen.cpp are related to operations with the * XSreensaver/XServer. This functions are basic/low level operations. They are * inspired, partly copied and modified from MPlayer * code (1.05pre). Thanks for the inspiration. \n \n * All 'higher level' class members of the class screen can be found here: \ref screen * \brief In this file can be found all screensaver related code. * \author Danny Kukawka, , * \date 2004 - 2006 */ // own headers #include "screen.h" #include "kpowersave_debug.h" /* needed for lXext C library linkage */ extern "C" { #include #include #include } // KDE Headers #include /*! The default constructor of the class screen */ screen::screen() { kdDebugFuncIn(trace); xscreensaver_lock = NULL; xscreensaver_reset = NULL; gnomescreensaver_lock = NULL; gnomeScreensaverCheck = NULL; xlock = NULL; got_XScreensaver = false; checkDPMSStatus(); check_xscreensaver_timer_runs = false; SCREENSAVER_STATUS = -1; screen_save_dcop_ref = DCOPRef( "kdesktop", "KScreensaverIface" ); check_xscreensaver_timer = new TQTimer( this ); connect( check_xscreensaver_timer, TQT_SIGNAL(timeout()), this, TQT_SLOT(xscreensaver_ping() )); SCREENSAVER_STATUS = checkScreenSaverStatus(); kdDebugFuncOut(trace); } /*! The default destructor of the class screen */ screen::~screen() { kdDebugFuncIn(trace); } /*! * To enable/disable the KScreensaver/Xscreensaver. * \param enable true: activate/enable screensaver / false: deactivate/disable screensacer * \return the result of try to set the screensaver * \retval true if screensaver set correct * \retval false if there is a error */ bool screen::setScreenSaver(bool enable){ kdDebugFuncIn(trace); if(SCREENSAVER_STATUS == -1) SCREENSAVER_STATUS = checkScreenSaverStatus(); if((SCREENSAVER_STATUS == 1) || (SCREENSAVER_STATUS == 0)){ screen_save_dcop_ref.send( "enable", enable); kdDebugFuncOut(trace); return true; } if(SCREENSAVER_STATUS == 11 || SCREENSAVER_STATUS == 10){ if(enable) { check_xscreensaver_timer->stop(); check_xscreensaver_timer_runs = false; } else { check_xscreensaver_timer->start( xScreenSaver_timer_interval ); check_xscreensaver_timer_runs = true; } kdDebugFuncOut(trace); return true; } else { kdDebugFuncOut(trace); return false; } } /* * * * * * this inspired, partly copied and modified from MPlayer Code (1.05pre) * START Section */ //! to handle information about wrong XWindows /*! * This integer represent information about XWindows. * - got_badwindow == True: if the searched Window is wrong or if there is a problem/error * - got_badwindow == False: if there is no problem/error */ static int got_badwindow; //! ErrorHandler /*! Errorhandler for all X-Server related operations */ static XErrorHandler defaultHandler; //! to find/handle bad XWindows / XSetErrorHandler /*! * This function is involved by the search for the window of the Xscreensaver. By this * function we seperate the BadWindow-error and set \ref got_badwindow if we get a BadWindow. * For more information take a look at the XServer Documentation! * \param dpy pointer to the active X-Display * \param error pointer to XErrorEvent * \return a info about a window-error * \retval 0 if the window is a BadWindow as a integer * \retval n the errorID/XErrorHandler if there is a error != BadWindow */ static int badwindow_handler(Display * dpy, XErrorEvent * error) { if (error->error_code != BadWindow) return (*defaultHandler) (dpy, error); got_badwindow = True; return 0; } //! to find the X-window of XScreensaver /*! * This function search for the X-Window of the active/activated XScreensaver. * \param dpy pointer to the active X-Display * \return The WindowID of the active XScreensaver. * \retval 0 if no Windows/Xscreensaver was found * \retval n ID of the founded XScreensaver window */ static Window find_xscreensaver_window(Display * dpy) { kdDebugFuncIn(trace); Window root = RootWindowOfScreen(DefaultScreenOfDisplay(dpy)); Window root2, parent, *kids; Window retval = 0; Atom xs_version; unsigned int i; unsigned int nkids = 0; xs_version = XInternAtom(dpy, "_SCREENSAVER_VERSION", True); if (!(xs_version != None && XQueryTree(dpy, root, &root2, &parent, &kids, &nkids) && kids && nkids)) { kdDebugFuncOut(trace); return 0; } defaultHandler = XSetErrorHandler(badwindow_handler); for (i = 0; i < nkids; i++) { Atom type; int format, status; unsigned long nitems, bytesafter; unsigned char *v; got_badwindow = False; status = XGetWindowProperty(dpy, kids[i], xs_version, 0, 200, False, XA_STRING, &type, &format, &nitems, &bytesafter, &v); XSync(dpy, False); if (got_badwindow) status = BadWindow; if (status == Success && type != None){ retval = kids[i]; break; } } XFree(kids); XSetErrorHandler(defaultHandler); kdDebugFuncOut(trace); return retval; } /*! * This function is used to ping the XScreensaver. There is no direct way to stop * the XScreensaver without to kill/stop an restart or modify config-files of the * current user. \n \n * We ping the xscreensaver as defined in the TQTimer-interval \ref xScreenSaver_timer_interval . * The value of \ref xScreenSaver_timer_interval is 58 sec at the moment. The intervall must be * smaller then 1 minute (this is the smallest interval of Xscreensaver a.t.m.). */ void screen::xscreensaver_ping(){ kdDebugFuncIn(trace); if(!got_XScreensaver) { mDisplay = tqt_xdisplay(); xs_windowid = find_xscreensaver_window(mDisplay); Atom deactivate = XInternAtom(mDisplay, "DEACTIVATE", False); Atom screensaver = XInternAtom(mDisplay, "SCREENSAVER", False); ev.xany.type = ClientMessage; ev.xclient.display = mDisplay; ev.xclient.window = xs_windowid; ev.xclient.message_type = screensaver; ev.xclient.format = 32; memset(&ev.xclient.data, 0, sizeof(ev.xclient.data)); ev.xclient.data.l[0] = (long) deactivate; if(xs_windowid != 0) got_XScreensaver = true; } if(got_XScreensaver){ if(XSendEvent(mDisplay, xs_windowid, False, 0L, &ev) == 0){ if(check_xscreensaver_timer->isActive()) { check_xscreensaver_timer->stop(); this->got_XScreensaver = false; } } XSync(mDisplay, False); } kdDebugFuncOut(trace); } /* * END Section * * * * * * */ /*! * Checks if KScreenSaver or XscreenSaver is activated * \return The result of the check as an integer value. * \retval 0 KScreensaver is disabled * \retval 1 KScreensaver is activated * \retval 10 Xscreensaver is not found or not running * \retval 11 Xscreensaver is activated * \retval 99 gnome-screensaver check is running * \retval -1 else */ int screen::checkScreenSaverStatus() { kdDebugFuncIn(trace); bool get_reply = false; int kScreenSaver_tmp_status = -1; int check = -1; // check for KScreenSaver DCOPReply reply = screen_save_dcop_ref.call("isEnabled()"); if(reply.isValid()){ if(reply.get(get_reply)){ if(get_reply) return 1; /* don't return status her because we must also check if * XScreensaver is activated !!! */ else kScreenSaver_tmp_status = 0; } } // check for XScreensaver if (got_XScreensaver) return 11; else if(!got_XScreensaver) { Display *dpy = tqt_xdisplay(); Window windowid = find_xscreensaver_window(dpy); if(windowid == 0) { //Xscreensaver not detected check_xscreensaver_timer->stop(); // KScreensaver activ and no XScreensaver found if(kScreenSaver_tmp_status == 0) return 0; // no KScreensaver and no XScreensaver found else check = 10; } else return 11; } // check for gnome-screen-saver if (check == 10) { delete gnomeScreensaverCheck; gnomeScreensaverCheck = new TDEProcess; *gnomeScreensaverCheck << "gnome-screensaver-command" << "--query"; connect( gnomeScreensaverCheck , TQT_SIGNAL(processExited(TDEProcess *)),TQT_SLOT(getGSExited(TDEProcess *))); if(!gnomeScreensaverCheck->start(TDEProcess::NotifyOnExit)) { delete gnomeScreensaverCheck; gnomeScreensaverCheck = NULL; return 10; } else return 99; } return -1; } /*! * \b TQT_SLOT which called if the call of gnomescreensaver-command exited * \param gnomecheckcommand the KPocess which called this SLOT */ void screen::getGSExited (TDEProcess *gnomecheckcommand) { kdDebugFuncIn(trace); if (gnomecheckcommand->normalExit()){ if (gnomecheckcommand->exitStatus() == 1) SCREENSAVER_STATUS = 10; else if (gnomecheckcommand->exitStatus() == 0) SCREENSAVER_STATUS = 20; } else { SCREENSAVER_STATUS = 10; } delete gnomeScreensaverCheck; gnomeScreensaverCheck=NULL; kdDebugFuncOut(trace); return; } /*! * This function check if DMPS is activated on the active X-Server. * \return Integer value with the result of the check * \retval 1 if DMPS is enabled * \retval 0 if DMPS is disabled * \retval -1 if there is a error */ int screen::checkDPMSStatus(){ kdDebugFuncIn(trace); CARD16 state; BOOL onoff; int dummy; Display *dpy = tqt_xdisplay(); if (!DPMSQueryExtension(dpy, &dummy, &dummy) || !DPMSCapable(dpy)){ has_DPMS = false; kdDebugFuncOut(trace); return -1; } else has_DPMS = true; DPMSInfo(dpy, &state, &onoff); if(onoff) { kdDebugFuncOut(trace); return 1; } else { kdDebugFuncOut(trace); return 0; } } /*! * To set DPMS on X-Server on/off. * \param enable true: activate/enable DMPS / false: deactivate/disable DPMS * \return the result of try to set DPMS * \retval true if DMPS correct set false * \retval false if fail (DPMS not supported) * \todo \li check/evaluate for errormessages * \li check if DPMS-Settings correct set if DPMSEnable(dpy) used */ bool screen::setDPMS( bool enable ){ kdDebugFuncIn(trace); defaultHandler = XSetErrorHandler(badwindow_handler); Display *dpy = tqt_xdisplay(); int dummy; if (!DPMSQueryExtension(dpy, &dummy, &dummy) || !DPMSCapable(dpy)){ has_DPMS = false; XSetErrorHandler(defaultHandler); kdDebugFuncOut(trace); return false; } if(enable) DPMSEnable(dpy); else DPMSDisable(dpy); XFlush(dpy); XSetErrorHandler(defaultHandler); kdDebugFuncOut(trace); return true; } /*! * This function set the Timeouts for DPMS for the X-Server. * \param standby_timeout time in seconds to stand-by the display as integer value * \param suspend_timeout time in seconds to suspend the display as integer value * \param off_timeout time in seconds to switch off the display as integer value * \return the result of try to set DPMS-Timeouts * \retval true if DMPS correct set false * \retval false if fail (DPMS not supported) */ bool screen::setDPMSTimeouts( int standby_timeout, int suspend_timeout, int off_timeout){ kdDebugFuncIn(trace); //XErrFunc defaultHandler; defaultHandler = XSetErrorHandler(badwindow_handler); Display *dpy = tqt_xdisplay(); int dummy; if (!DPMSQueryExtension(dpy, &dummy, &dummy) || !DPMSCapable(dpy)){ has_DPMS = false; XSetErrorHandler(defaultHandler); kdDebugFuncOut(trace); return false; } DPMSSetTimeouts(dpy, 60 * standby_timeout, 60 * suspend_timeout, 60 * off_timeout); XFlush(dpy); XSetErrorHandler(defaultHandler); kdDebugFuncOut(trace); return true; } /*! * Use this function to lock the screen. This function use automatically the right * method for KDE or GNOME. * \return boolean with the result of the operation * \retval true if the requested method worked * \retval false if there was a error */ bool screen::lockScreen(){ kdDebugFuncIn(trace); // screensaver status known? if(SCREENSAVER_STATUS == -1) SCREENSAVER_STATUS = checkScreenSaverStatus(); // set lock for KScreensaver if((SCREENSAVER_STATUS == 1) || (SCREENSAVER_STATUS == 0)){ DCOPReply reply = screen_save_dcop_ref.call("lock"); if ( reply.isValid() ) { return true; } else { kdWarning() << "Could not lock KScreensaver, try XScreensaver as fallback." << endl; goto xscreensaver; } } // set lock for XScreensaver else if(SCREENSAVER_STATUS == 11){ xscreensaver: delete xscreensaver_lock; xscreensaver_lock = new TDEProcess; *xscreensaver_lock << "xscreensaver-command" << "-lock"; connect(xscreensaver_lock, TQT_SIGNAL(processExited(TDEProcess*)), this, TQT_SLOT(cleanProcess(TDEProcess*))); bool status = xscreensaver_lock->start(TDEProcess::DontCare); if(!status) { delete xscreensaver_lock; xscreensaver_lock = NULL; } return status; } // lock with gnome-screen-saver else if(SCREENSAVER_STATUS == 20){ delete gnomescreensaver_lock; gnomescreensaver_lock = new TDEProcess; *gnomescreensaver_lock << "gnome-screensaver-command" << "--lock"; connect(gnomescreensaver_lock, TQT_SIGNAL(processExited(TDEProcess*)), this, TQT_SLOT(cleanProcess(TDEProcess*))); bool status = gnomescreensaver_lock->start(TDEProcess::DontCare); if(!status) { delete gnomescreensaver_lock; gnomescreensaver_lock=NULL; } return status; } // set lock for xlock --> no tdescreensaver, no xscreensaver present and // the check for gnome screensaver is not finished. This should normaly // not happen, but in this case we use xlock else if(SCREENSAVER_STATUS == 10 || SCREENSAVER_STATUS == 99){ delete xlock; xlock = new TDEProcess; *xlock << "xlock"; //<< "-mode" << "blank"; connect(xlock, TQT_SIGNAL(processExited(TDEProcess*)), this, TQT_SLOT(cleanProcess(TDEProcess*))); bool status = xlock->start(TDEProcess::DontCare); if(!status) { delete xlock; xlock = NULL; } return status; } else return false; } /*! * Use this function to lock the screen with a specified lock method. * \param lock_withMethod a TQString, which contain the alias for the lock * command. * \return boolean with the result of the operation * \retval true if the requested method worked * \retval false if there was a error * \todo check if we should also set blank only if the user would like!!! */ bool screen::lockScreen( TQString lock_withMethod ) { kdDebugFuncIn(trace); if (lock_withMethod == "automatic") { lockScreen(); return true; } else if (lock_withMethod == "xlock") { delete xlock; xlock = new TDEProcess; *xlock << "xlock"; connect(xlock, TQT_SIGNAL(processExited(TDEProcess*)), this, TQT_SLOT(cleanProcess(TDEProcess*))); bool status = xlock->start(TDEProcess::DontCare); if(!status) { delete xlock; xlock=NULL; } return status; } else if (lock_withMethod == "gnomescreensaver") { gnomescreensaver_lock = new TDEProcess; *gnomescreensaver_lock << "gnome-screensaver-command" << "--lock"; connect(gnomescreensaver_lock, TQT_SIGNAL(processExited(TDEProcess*)), this, TQT_SLOT(cleanProcess(TDEProcess*))); bool status = gnomescreensaver_lock->start(TDEProcess::DontCare); if(!status) { delete gnomescreensaver_lock; gnomescreensaver_lock = NULL; } return status; } else { // screensaver status known? SCREENSAVER_STATUS = checkScreenSaverStatus(); if (lock_withMethod == "tdescreensaver") { if((SCREENSAVER_STATUS == 1) || (SCREENSAVER_STATUS == 0)){ DCOPReply reply = screen_save_dcop_ref.call("lock"); if ( reply.isValid() ) { return true; } else { kdWarning() << "Could not call lock for KScreensaver, try XScreensaver " << "as fallback." << endl; goto xscreensaver; } } else return false; } else if (lock_withMethod == "xscreensaver") { if(SCREENSAVER_STATUS == 11){ xscreensaver: delete xscreensaver_lock; xscreensaver_lock = new TDEProcess; *xscreensaver_lock << "xscreensaver-command" << "-lock"; connect(xscreensaver_lock, TQT_SIGNAL(processExited(TDEProcess*)), this, TQT_SLOT(cleanProcess(TDEProcess*))); bool status = xscreensaver_lock->start(TDEProcess::DontCare); if(!status) { delete xscreensaver_lock; xscreensaver_lock = NULL; } return status; } else return false; } else return false; } return false; } /*! * Use this function to set the screensaver to 'blank only' instead of * using the in KDE or GNOME set screensaver. * \todo find a way to set the xscreensaver to 'blank only' */ void screen::blankOnlyScreen( bool blankonly ){ kdDebugFuncIn(trace); if(SCREENSAVER_STATUS == -1) SCREENSAVER_STATUS = checkScreenSaverStatus(); // set KScreensaver if((SCREENSAVER_STATUS == 1) || (SCREENSAVER_STATUS == 0)){ screen_save_dcop_ref.send("setBlankOnly", blankonly); } // set XScreensaver else if(SCREENSAVER_STATUS == 11){ // implement something !!! } kdDebugFuncOut(trace); } /*! * Use this function to reset the KDE screensaver/DPMS settings * \return boolean with the result of the operation * \retval true if the reset was called * \retval false if there was a error */ bool screen::resetKDEScreensaver(){ kdDebugFuncIn(trace); if(SCREENSAVER_STATUS == -1) SCREENSAVER_STATUS = checkScreenSaverStatus(); // do this only if the screensaver is not running if(SCREENSAVER_STATUS == 0){ DCOPReply reply = screen_save_dcop_ref.call("configure"); if ( reply.isValid() ) { kdDebugFuncOut(trace); return true; } else { kdWarning() << "Could not call configure() for the KDE screensaver." << endl; kdDebugFuncOut(trace); return false; } } else { kdDebugFuncOut(trace); return false; } } /*! * Use this function to reset the xscreensaver settings * \return boolean with the result of the operation * \retval true if the reset was called * \retval false if there was a error */ bool screen::resetXScreensaver(){ kdDebugFuncIn(trace); if(checkScreenSaverStatus() == 11) { delete xscreensaver_reset; xscreensaver_reset = new TDEProcess; *xscreensaver_reset << "xscreensaver-command" << "-restart"; connect(xscreensaver_reset, TQT_SIGNAL(processExited(TDEProcess*)), this, TQT_SLOT(cleanProcess(TDEProcess*))); bool status = xscreensaver_reset->start(TDEProcess::DontCare); if(!status) { delete xscreensaver_reset; xscreensaver_reset = NULL; } kdDebugFuncOut(trace); return status; } else { kdDebugFuncOut(trace); return false; } } /*! * function to call xset commandline tool to force shutdown the display with dpms */ void screen::forceDPMSOff() { kdDebugFuncIn(trace); TDEProcess *xset = new TDEProcess; *xset << "xset" << "dpms" << "force" << "off"; connect(xset, TQT_SIGNAL(processExited(TDEProcess*)), this, TQT_SLOT(cleanProcess(TDEProcess*))); if(!xset->start()) { delete xset; } kdDebugFuncOut(trace); } /*! * function to clean TDEProcess objects */ void screen::cleanProcess(TDEProcess* proc) { delete proc; proc = NULL; } /*! * function to fake a key event for the shift key. Use this to show the login * passwd dialog after suspend if we locked the screen. */ void screen::fakeShiftKeyEvent() { kdDebugFuncIn(trace); Display *dpy = tqt_xdisplay(); if (dpy) { XTestFakeKeyEvent(dpy, 62, 1, 0); XTestFakeKeyEvent(dpy, 62, 0, 0); XFlush(dpy); } kdDebugFuncOut(trace); return; } #include "screen.moc"