1 // Core.cc --- The main controller
2 //
3 // Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 Rob Caelers & Raymond Penners
4 // All rights reserved.
5 //
6 // This program is free software: you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation, either version 3 of the License, or
9 // (at your option) any later version.
10 //
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 // GNU General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public License
17 // along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 //
19 
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23 
24 #ifdef PLATFORM_OS_OSX
25 #include "OSXHelpers.hh"
26 #endif
27 
28 #include "debug.hh"
29 
30 #include <stdlib.h>
31 #include <assert.h>
32 #include <iostream>
33 #include <fstream>
34 #include <sstream>
35 
36 #include "Core.hh"
37 
38 #include "Util.hh"
39 #include "IApp.hh"
40 #include "ICoreEventListener.hh"
41 #include "ActivityMonitor.hh"
42 #include "TimerActivityMonitor.hh"
43 #include "Break.hh"
44 #include "ConfiguratorFactory.hh"
45 #include "Configurator.hh"
46 #include "CoreConfig.hh"
47 #include "Statistics.hh"
48 #include "BreakControl.hh"
49 #include "Timer.hh"
50 #include "TimePredFactory.hh"
51 #include "TimePred.hh"
52 #include "TimeSource.hh"
53 #include "InputMonitorFactory.hh"
54 
55 #ifdef HAVE_DISTRIBUTION
56 #include "DistributionManager.hh"
57 #include "IdleLogManager.hh"
58 #include "PacketBuffer.hh"
59 #ifndef NDEBUG
60 #include "FakeActivityMonitor.hh"
61 #endif
62 #endif
63 
64 #ifdef HAVE_GCONF
65 #include <gconf/gconf-client.h>
66 #endif
67 
68 #ifdef HAVE_DBUS
69 #include "dbus/DBusFactory.hh"
70 #if defined(PLATFORM_OS_WIN32_NATIVE)
71 #undef interface
72 #endif
73 #include "dbus/IDBus.hh"
74 #include "dbus/DBusException.hh"
75 #include "DBusWorkrave.hh"
76 #ifdef HAVE_TESTS
77 #include "Test.hh"
78 #endif
79 #endif
80 
81 Core *Core::instance = NULL;
82 
83 const char *WORKRAVESTATE="WorkRaveState";
84 const int SAVESTATETIME = 60;
85 
86 #define DBUS_PATH_WORKRAVE         "/org/workrave/Workrave/Core"
87 #define DBUS_SERVICE_WORKRAVE      "org.workrave.Workrave"
88 
89 //! Constructs a new Core.
Core()90 Core::Core() :
91   last_process_time(0),
92   master_node(true),
93   configurator(NULL),
94   monitor(NULL),
95   application(NULL),
96   statistics(NULL),
97   operation_mode(OPERATION_MODE_NORMAL),
98   operation_mode_regular(OPERATION_MODE_NORMAL),
99   usage_mode(USAGE_MODE_NORMAL),
100   core_event_listener(NULL),
101   powersave(false),
102   powersave_resume_time(0),
103   insist_policy(ICore::INSIST_POLICY_HALT),
104   active_insist_policy(ICore::INSIST_POLICY_INVALID),
105   resume_break(BREAK_ID_NONE),
106   local_state(ACTIVITY_IDLE),
107   monitor_state(ACTIVITY_UNKNOWN)
108 #ifdef HAVE_DISTRIBUTION
109   ,
110   dist_manager(NULL),
111   remote_state(ACTIVITY_IDLE),
112   idlelog_manager(NULL)
113 #  ifndef NDEBUG
114   ,
115   fake_monitor(NULL)
116 #  endif
117 #endif
118 {
119   TRACE_ENTER("Core::Core");
120   current_time = time(NULL);
121 
122   assert(! instance);
123   instance = this;
124 
125   TRACE_EXIT();
126 }
127 
128 
129 //! Destructor.
~Core()130 Core::~Core()
131 {
132   TRACE_ENTER("Core::~Core");
133 
134   save_state();
135 
136   if (monitor != NULL)
137     {
138       monitor->terminate();
139     }
140 
141   delete statistics;
142   delete monitor;
143   delete configurator;
144 
145 #ifdef HAVE_DISTRIBUTION
146   if (idlelog_manager != NULL)
147     {
148       idlelog_manager->terminate();
149       delete idlelog_manager;
150     }
151 
152   delete dist_manager;
153 #ifndef NDEBUG
154   delete fake_monitor;
155 #endif
156 #endif
157 
158   TRACE_EXIT();
159 }
160 
161 
162 /********************************************************************************/
163 /**** Initialization                                                       ******/
164 /********************************************************************************/
165 
166 
167 //! Initializes the core.
168 void
init(int argc,char ** argv,IApp * app,const char * display_name)169 Core::init(int argc, char **argv, IApp *app, const char *display_name)
170 {
171   application = app;
172   this->argc = argc;
173   this->argv = argv;
174 
175   init_configurator();
176   init_monitor(display_name);
177 
178 #ifdef HAVE_DISTRIBUTION
179   init_distribution_manager();
180 #endif
181 
182   init_breaks();
183   init_statistics();
184   init_bus();
185 
186   load_state();
187   load_misc();
188 }
189 
190 
191 //! Initializes the configurator.
192 void
init_configurator()193 Core::init_configurator()
194 {
195   string ini_file = Util::complete_directory("workrave.ini", Util::SEARCH_PATH_CONFIG);
196 
197   if (Util::file_exists(ini_file))
198     {
199       configurator = ConfiguratorFactory::create(ConfiguratorFactory::FormatIni);
200       configurator->load(ini_file);
201     }
202   else
203     {
204 #if defined(HAVE_GCONF)
205       gconf_init(argc, argv, NULL);
206       g_type_init();
207 #endif
208 
209       configurator = ConfiguratorFactory::create(ConfiguratorFactory::FormatNative);
210 #if defined(HAVE_GDOME)
211       if (configurator == NULL)
212         {
213           string configFile = Util::complete_directory("config.xml", Util::SEARCH_PATH_CONFIG);
214           configurator = ConfiguratorFactory::create(ConfiguratorFactory::FormatXml);
215 
216 #  if defined(PLATFORM_OS_UNIX)
217           if (configFile == "" || configFile == "config.xml")
218             {
219               configFile = Util::get_home_directory() + "config.xml";
220             }
221 #  endif
222           if (configFile != "")
223             {
224               configurator->load(configFile);
225             }
226         }
227 #endif
228       if (configurator == NULL)
229         {
230           ini_file = Util::get_home_directory() + "workrave.ini";
231           configurator = ConfiguratorFactory::create(ConfiguratorFactory::FormatIni);
232           configurator->load(ini_file);
233           configurator->save(ini_file);
234         }
235     }
236 
237   string home;
238   if (configurator->get_value(CoreConfig::CFG_KEY_GENERAL_DATADIR, home) &&
239       home != "")
240     {
241       Util::set_home_directory(home);
242     }
243 }
244 
245 //! Initializes the communication bus.
246 void
init_bus()247 Core::init_bus()
248 {
249 #ifdef HAVE_DBUS
250   try
251     {
252       dbus = workrave::dbus::DBusFactory::create();
253       dbus->init();
254 
255       extern void init_DBusWorkrave(workrave::dbus::IDBus::Ptr dbus);
256       init_DBusWorkrave(dbus);
257 
258       dbus->connect(DBUS_PATH_WORKRAVE, "org.workrave.CoreInterface", this);
259       dbus->connect(DBUS_PATH_WORKRAVE, "org.workrave.ConfigInterface", configurator);
260       dbus->register_object_path(DBUS_PATH_WORKRAVE);
261 
262 #ifdef HAVE_TESTS
263       dbus->connect("/org/workrave/Workrave/Debug", "org.workrave.DebugInterface", Test::get_instance());
264       dbus->register_object_path("/org/workrave/Workrave/Debug");
265 #endif
266     }
267   catch (workrave::dbus::DBusException &)
268     {
269     }
270 #endif
271 }
272 
273 
274 //! Initializes the activity monitor.
275 void
init_monitor(const char * display_name)276 Core::init_monitor(const char *display_name)
277 {
278 #ifdef HAVE_DISTRIBUTION
279 #ifndef NDEBUG
280   fake_monitor = NULL;
281   const char *env = getenv("WORKRAVE_FAKE");
282   if (env != NULL)
283     {
284       fake_monitor = new FakeActivityMonitor();
285     }
286 #endif
287 #endif
288 
289   InputMonitorFactory::init(display_name);
290 
291   configurator->set_value(CoreConfig::CFG_KEY_MONITOR_SENSITIVITY, 3, CONFIG_FLAG_DEFAULT);
292 
293   monitor = new ActivityMonitor();
294   load_monitor_config();
295 
296   configurator->add_listener(CoreConfig::CFG_KEY_MONITOR, this);
297 }
298 
299 
300 //! Initializes all breaks.
301 void
init_breaks()302 Core::init_breaks()
303 {
304   for (int i = 0; i < BREAK_ID_SIZEOF; i++)
305     {
306       breaks[i].init(BreakId(i), application);
307     }
308   application->set_break_response(this);
309 }
310 
311 
312 #ifdef HAVE_DISTRIBUTION
313 //! Initializes the monitor based on the specified configuration.
314 void
init_distribution_manager()315 Core::init_distribution_manager()
316 {
317   dist_manager = new DistributionManager();
318   assert(dist_manager != NULL);
319 
320   dist_manager->init(configurator);
321   dist_manager->register_client_message(DCM_BREAKS, DCMT_MASTER, this);
322   dist_manager->register_client_message(DCM_TIMERS, DCMT_MASTER, this);
323   dist_manager->register_client_message(DCM_MONITOR, DCMT_MASTER, this);
324   dist_manager->register_client_message(DCM_IDLELOG, DCMT_SIGNON, this);
325   dist_manager->register_client_message(DCM_BREAKCONTROL, DCMT_PASSIVE, this);
326 
327   dist_manager->add_listener(this);
328 
329   idlelog_manager = new IdleLogManager(dist_manager->get_my_id(), this);
330   idlelog_manager->init();
331 }
332 #endif
333 
334 
335 //! Initializes the statistics.
336 void
init_statistics()337 Core::init_statistics()
338 {
339   statistics = new Statistics();
340   statistics->init(this);
341 }
342 
343 
344 //! Loads the configuration of the monitor.
345 void
load_monitor_config()346 Core::load_monitor_config()
347 {
348   TRACE_ENTER("Core::load_monitor_config");
349 
350   int noise;
351   int activity;
352   int idle;
353   int sensitivity;
354 
355   assert(configurator != NULL);
356   assert(monitor != NULL);
357 
358   if (! configurator->get_value(CoreConfig::CFG_KEY_MONITOR_NOISE, noise))
359     noise = 9000;
360   if (! configurator->get_value(CoreConfig::CFG_KEY_MONITOR_ACTIVITY, activity))
361     activity = 1000;
362   if (! configurator->get_value(CoreConfig::CFG_KEY_MONITOR_IDLE, idle))
363     idle = 5000;
364   if (! configurator->get_value(CoreConfig::CFG_KEY_MONITOR_SENSITIVITY, sensitivity))
365     sensitivity = 3;
366 
367   // Pre 1.0 compatibility...
368   if (noise < 50)
369     {
370       noise *= 1000;
371       configurator->set_value(CoreConfig::CFG_KEY_MONITOR_NOISE, noise);
372     }
373 
374   if (activity < 50)
375     {
376       activity *= 1000;
377       configurator->set_value(CoreConfig::CFG_KEY_MONITOR_ACTIVITY, activity);
378     }
379 
380   if (idle < 50)
381     {
382       idle *= 1000;
383       configurator->set_value(CoreConfig::CFG_KEY_MONITOR_IDLE, idle);
384     }
385 
386 
387   TRACE_MSG("Monitor config = " << noise << " " << activity << " " << idle);
388 
389   monitor->set_parameters(noise, activity, idle, sensitivity);
390   TRACE_EXIT();
391 }
392 
393 
394 //! Notification that the configuration has changed.
395 void
config_changed_notify(const string & key)396 Core::config_changed_notify(const string &key)
397 {
398   TRACE_ENTER_MSG("Core::config_changed_notify", key);
399   string::size_type pos = key.find('/');
400   string path;
401 
402   if (pos != string::npos)
403     {
404       path = key.substr(0, pos);
405     }
406 
407   if (path == CoreConfig::CFG_KEY_MONITOR)
408     {
409       load_monitor_config();
410     }
411 
412   if (key == CoreConfig::CFG_KEY_OPERATION_MODE)
413     {
414       int mode;
415       if (! get_configurator()->get_value(CoreConfig::CFG_KEY_OPERATION_MODE, mode))
416         {
417           mode = OPERATION_MODE_NORMAL;
418         }
419       if (mode < 0 || mode >= OPERATION_MODE_SIZEOF)
420         {
421           mode = OPERATION_MODE_NORMAL;
422         }
423       TRACE_MSG("Setting operation mode");
424       set_operation_mode_internal(OperationMode(mode), false);
425     }
426 
427   if (key == CoreConfig::CFG_KEY_USAGE_MODE)
428     {
429       int mode;
430       if (! get_configurator()->get_value(CoreConfig::CFG_KEY_USAGE_MODE, mode))
431         {
432           mode = USAGE_MODE_NORMAL;
433         }
434       if (mode < 0 || mode >= USAGE_MODE_SIZEOF)
435         {
436           mode = USAGE_MODE_NORMAL;
437         }
438       TRACE_MSG("Setting usage mode");
439       set_usage_mode_internal(UsageMode(mode), false);
440     }
441   TRACE_EXIT();
442 }
443 
444 
445 /********************************************************************************/
446 /**** TimeSource interface                                                 ******/
447 /********************************************************************************/
448 
449 //! Retrieve the current time.
450 time_t
get_time() const451 Core::get_time() const
452 {
453   return current_time;
454 }
455 
456 
457 /********************************************************************************/
458 /**** Core Interface                                                       ******/
459 /********************************************************************************/
460 
461 //! Returns the specified timer.
462 Timer *
get_timer(BreakId id) const463 Core::get_timer(BreakId id) const
464 {
465   if (id >= 0 && id < BREAK_ID_SIZEOF)
466     {
467       return breaks[id].get_timer();
468     }
469   else
470     {
471       return NULL;
472     }
473 }
474 
475 
476 //! Returns the specified timer.
477 Timer *
get_timer(string name) const478 Core::get_timer(string name) const
479 {
480   for (int i = 0; i < BREAK_ID_SIZEOF; i++)
481     {
482       if (breaks[i].get_name() == name)
483         {
484           return breaks[i].get_timer();
485         }
486     }
487   return NULL;
488 }
489 
490 
491 //! Returns the configurator.
492 Configurator *
get_configurator() const493 Core::get_configurator() const
494 {
495   return configurator;
496 }
497 
498 
499 //! Returns the activity monitor.
500 IActivityMonitor *
get_activity_monitor() const501 Core::get_activity_monitor() const
502 {
503   return monitor;
504 }
505 
506 
507 //! Returns the statistics.
508 Statistics *
get_statistics() const509 Core::get_statistics() const
510 {
511   return statistics;
512 }
513 
514 
515 //! Returns the specified break controller.
516 Break *
get_break(BreakId id)517 Core::get_break(BreakId id)
518 {
519   assert(id >= 0 && id < BREAK_ID_SIZEOF);
520   return &breaks[id];
521 }
522 
523 //! Returns the specified break controller.
524 Break *
get_break(std::string name)525 Core::get_break(std::string name)
526 {
527   for (int i = 0; i < BREAK_ID_SIZEOF; i++)
528     {
529       if (breaks[i].get_name() == name)
530         {
531           return &breaks[i];
532         }
533     }
534   return NULL;
535 }
536 
537 
538 std::string
get_break_stage(BreakId id)539 Core::get_break_stage(BreakId id)
540 {
541   if (id >= 0 && id < BREAK_ID_SIZEOF)
542     {
543       return breaks[id].get_break_control()->get_current_stage();
544     }
545   else
546     {
547       return "";
548     }
549 }
550 
551 #ifdef HAVE_DISTRIBUTION
552 //! Returns the distribution manager.
553 DistributionManager *
get_distribution_manager() const554 Core::get_distribution_manager() const
555 {
556   return dist_manager;
557 }
558 #endif
559 
560 
561 //! Retrieves the operation mode.
562 OperationMode
get_operation_mode()563 Core::get_operation_mode()
564 {
565     return operation_mode;
566 }
567 
568 //! Retrieves the regular operation mode.
569 OperationMode
get_operation_mode_regular()570 Core::get_operation_mode_regular()
571 {
572     /* operation_mode_regular is the same as operation_mode unless there's an
573     override in place, in which case operation_mode is the current override mode and
574     operation_mode_regular is the mode that will be restored once all overrides are removed
575     */
576     return operation_mode_regular;
577 }
578 
579 //! Checks if operation_mode is an override.
580 bool
is_operation_mode_an_override()581 Core::is_operation_mode_an_override()
582 {
583     return !!operation_mode_overrides.size();
584 }
585 
586 //! Sets the operation mode.
587 void
set_operation_mode(OperationMode mode)588 Core::set_operation_mode(OperationMode mode)
589 {
590     set_operation_mode_internal( mode, true );
591 }
592 
593 //! Temporarily overrides the operation mode.
594 void
set_operation_mode_override(OperationMode mode,const std::string & id)595 Core::set_operation_mode_override( OperationMode mode, const std::string &id )
596 {
597     if( !id.size() )
598         return;
599 
600     set_operation_mode_internal( mode, false, id );
601 }
602 
603 //! Removes the overriden operation mode.
604 void
remove_operation_mode_override(const std::string & id)605 Core::remove_operation_mode_override( const std::string &id )
606 {
607     TRACE_ENTER( "Core::remove_operation_mode_override" );
608 
609     if( !id.size() || !operation_mode_overrides.count( id ) )
610         return;
611 
612     operation_mode_overrides.erase( id );
613 
614     /* If there are other overrides still in the queue then pass in the first
615     override in the map. set_operation_mode_internal() will then search the
616     map for the most important override and set it as the active operation mode.
617     */
618     if( operation_mode_overrides.size() )
619     {
620         set_operation_mode_internal(
621             operation_mode_overrides.begin()->second,
622             false,
623             operation_mode_overrides.begin()->first
624             );
625     }
626     else
627     {
628         /* if operation_mode_regular is the same as the active operation mode then just
629         signal the mode has changed. During overrides the signal is not sent so it needs to
630         be sent now. Because the modes are the same it would not be called by
631         set_operation_mode_internal().
632         */
633         if( operation_mode_regular == operation_mode )
634         {
635             TRACE_MSG( "Only calling core_event_operation_mode_changed()." );
636             if( core_event_listener )
637                 core_event_listener->core_event_operation_mode_changed( operation_mode_regular );
638 
639 #ifdef HAVE_DBUS
640             org_workrave_CoreInterface *iface = org_workrave_CoreInterface::instance(dbus);
641             if (iface != NULL)
642               {
643                 iface->OperationModeChanged("/org/workrave/Workrave/Core", operation_mode_regular);
644               }
645 #endif
646         }
647         else
648             set_operation_mode_internal( operation_mode_regular, false );
649     }
650 
651     TRACE_EXIT();
652 }
653 
654 //! Set the operation mode.
655 void
set_operation_mode_internal(OperationMode mode,bool persistent,const std::string & override_id)656 Core::set_operation_mode_internal(
657     OperationMode mode,
658     bool persistent,
659     const std::string &override_id /* default param: empty string */
660     )
661 {
662   TRACE_ENTER_MSG("Core::set_operation_mode", ( persistent ? "persistent" : "" ) );
663 
664   if( override_id.size() )
665   {
666       TRACE_MSG( "override_id: " << override_id );
667   }
668 
669   TRACE_MSG( "Incoming/requested mode is "
670       << ( mode == OPERATION_MODE_NORMAL ? "OPERATION_MODE_NORMAL" :
671             mode == OPERATION_MODE_SUSPENDED ? "OPERATION_MODE_SUSPENDED" :
672                 mode == OPERATION_MODE_QUIET ? "OPERATION_MODE_QUIET" : "???" )
673       << ( override_id.size() ? " (override)" : " (regular)" )
674       );
675 
676   TRACE_MSG( "Current mode is "
677       << ( mode == OPERATION_MODE_NORMAL ? "OPERATION_MODE_NORMAL" :
678             mode == OPERATION_MODE_SUSPENDED ? "OPERATION_MODE_SUSPENDED" :
679                 mode == OPERATION_MODE_QUIET ? "OPERATION_MODE_QUIET" : "???" )
680       << ( operation_mode_overrides.size() ? " (override)" : " (regular)" )
681       );
682 
683   if( ( mode != OPERATION_MODE_NORMAL )
684       && ( mode != OPERATION_MODE_QUIET )
685       && ( mode != OPERATION_MODE_SUSPENDED )
686       )
687   {
688       TRACE_RETURN( "No change: incoming invalid" );
689       return;
690   }
691 
692   /* If the incoming operation mode is regular and the current operation mode is an
693   override then save the incoming operation mode and return.
694   */
695   if( !override_id.size() && operation_mode_overrides.size() )
696   {
697       operation_mode_regular = mode;
698 
699       int cm;
700       if( persistent
701           && ( !get_configurator()->get_value( CoreConfig::CFG_KEY_OPERATION_MODE, cm )
702               || ( cm != mode ) )
703           )
704           get_configurator()->set_value( CoreConfig::CFG_KEY_OPERATION_MODE, mode );
705 
706       TRACE_RETURN( "No change: current is an override type but incoming is regular" );
707       return;
708   }
709 
710   // If the incoming operation mode is tagged as an override
711   if( override_id.size() )
712   {
713       // Add this override to the map
714       operation_mode_overrides[ override_id ] = mode;
715 
716       /* Find the most important override. Override modes in order of importance:
717       OPERATION_MODE_SUSPENDED, OPERATION_MODE_QUIET, OPERATION_MODE_NORMAL
718       */
719       for( map<std::string, OperationMode>::iterator i = operation_mode_overrides.begin();
720           ( i != operation_mode_overrides.end() );
721           ++i
722           )
723       {
724           if( i->second == OPERATION_MODE_SUSPENDED )
725           {
726               mode = OPERATION_MODE_SUSPENDED;
727               break;
728           }
729 
730           if( ( i->second == OPERATION_MODE_QUIET )
731               && ( mode == OPERATION_MODE_NORMAL )
732               )
733           {
734               mode = OPERATION_MODE_QUIET;
735           }
736       }
737   }
738 
739 
740   if (operation_mode != mode)
741   {
742       TRACE_MSG( "Changing active operation mode to "
743           << ( mode == OPERATION_MODE_NORMAL ? "OPERATION_MODE_NORMAL" :
744                 mode == OPERATION_MODE_SUSPENDED ? "OPERATION_MODE_SUSPENDED" :
745                     mode == OPERATION_MODE_QUIET ? "OPERATION_MODE_QUIET" : "???" )
746           );
747 
748       OperationMode previous_mode = operation_mode;
749 
750       operation_mode = mode;
751 
752       if( !operation_mode_overrides.size() )
753           operation_mode_regular = operation_mode;
754 
755       if (operation_mode == OPERATION_MODE_SUSPENDED)
756       {
757           TRACE_MSG("Force idle");
758           force_idle();
759           monitor->suspend();
760           stop_all_breaks();
761 
762           for (int i = 0; i < BREAK_ID_SIZEOF; ++i)
763           {
764               if (breaks[i].is_enabled())
765               {
766                   breaks[i].get_timer()->set_insensitive_mode(INSENSITIVE_MODE_IDLE_ALWAYS);
767               }
768           }
769       }
770       else if (previous_mode == OPERATION_MODE_SUSPENDED)
771       {
772           // stop_all_breaks again will reset insensitive mode (that is good)
773           stop_all_breaks();
774           monitor->resume();
775       }
776 
777       if (operation_mode == OPERATION_MODE_QUIET)
778       {
779           stop_all_breaks();
780       }
781 
782       if( !operation_mode_overrides.size() )
783       {
784           /* The two functions in this block will trigger signals that can call back into this function.
785           Only if there are no overrides in place will that reentrancy be ok from here.
786           Otherwise the regular/user mode to restore would be overwritten.
787           */
788 
789           if( persistent )
790               get_configurator()->set_value( CoreConfig::CFG_KEY_OPERATION_MODE, operation_mode );
791 
792           if( core_event_listener )
793               core_event_listener->core_event_operation_mode_changed( operation_mode );
794 
795 #ifdef HAVE_DBUS
796           org_workrave_CoreInterface *iface = org_workrave_CoreInterface::instance(dbus);
797           if (iface != NULL)
798             {
799               iface->OperationModeChanged("/org/workrave/Workrave/Core", operation_mode);
800             }
801 #endif
802       }
803   }
804 
805   TRACE_EXIT();
806 }
807 
808 
809 //! Retrieves the usage mode.
810 UsageMode
get_usage_mode()811 Core::get_usage_mode()
812 {
813   return usage_mode;
814 }
815 
816 //! Sets the usage mode.
817 void
set_usage_mode(UsageMode mode)818 Core::set_usage_mode(UsageMode mode)
819 {
820   set_usage_mode_internal(mode, true);
821 }
822 
823 //! Sets the usage mode.
824 void
set_usage_mode_internal(UsageMode mode,bool persistent)825 Core::set_usage_mode_internal(UsageMode mode, bool persistent)
826 {
827   if (usage_mode != mode)
828     {
829       usage_mode = mode;
830 
831       for (int i = 0; i < BREAK_ID_SIZEOF; i++)
832         {
833           breaks[i].set_usage_mode(mode);
834         }
835 
836       if (persistent)
837         {
838           get_configurator()->set_value(CoreConfig::CFG_KEY_USAGE_MODE, mode);
839         }
840 
841       if (core_event_listener != NULL)
842         {
843           core_event_listener->core_event_usage_mode_changed(mode);
844 
845 #ifdef HAVE_DBUS
846           org_workrave_CoreInterface *iface = org_workrave_CoreInterface::instance(dbus);
847           if (iface != NULL)
848             {
849               iface->UsageModeChanged("/org/workrave/Workrave/Core", mode);
850             }
851 #endif
852         }
853     }
854 }
855 
856 //! Sets the listener for core events.
857 void
set_core_events_listener(ICoreEventListener * l)858 Core::set_core_events_listener(ICoreEventListener *l)
859 {
860   core_event_listener = l;
861 }
862 
863 
864 //! Forces the start of the specified break.
865 void
force_break(BreakId id,BreakHint break_hint)866 Core::force_break(BreakId id, BreakHint break_hint)
867 {
868   do_force_break(id, break_hint);
869 
870 #ifdef HAVE_DISTRIBUTION
871   send_break_control_message_bool_param(id, BCM_START_BREAK, break_hint);
872 #endif
873 }
874 
875 
876 //! Forces the start of the specified break.
877 void
do_force_break(BreakId id,BreakHint break_hint)878 Core::do_force_break(BreakId id, BreakHint break_hint)
879 {
880   TRACE_ENTER_MSG("Core::do_force_break", id);
881   BreakControl *microbreak_control = breaks[BREAK_ID_MICRO_BREAK].get_break_control();
882   BreakControl *breaker = breaks[id].get_break_control();
883 
884   if (id == BREAK_ID_REST_BREAK &&
885       (microbreak_control->get_break_state() == BreakControl::BREAK_ACTIVE))
886     {
887       microbreak_control->stop_break(false);
888       resume_break = BREAK_ID_MICRO_BREAK;
889       TRACE_MSG("Resuming Micro break");
890     }
891 
892   breaker->force_start_break(break_hint);
893   TRACE_EXIT();
894 }
895 
896 
897 //! Announces a change in time.
898 void
time_changed()899 Core::time_changed()
900 {
901   TRACE_ENTER("Core::time_changed");
902 
903   // In case out timezone changed..
904   tzset();
905 
906   // A change of system time idle handled by process_timewarp.
907   // This is used to handle a change in timezone on windows.
908   for (int i = 0; i < BREAK_ID_SIZEOF; i++)
909     {
910       breaks[i].get_timer()->shift_time(0);
911     }
912 
913   TRACE_EXIT();
914 }
915 
916 
917 //! Announces a powersave state.
918 void
set_powersave(bool down)919 Core::set_powersave(bool down)
920 {
921   TRACE_ENTER_MSG("Core::set_powersave", down);
922   TRACE_MSG(powersave << " " << powersave_resume_time << " " << operation_mode);
923 
924   if (down)
925     {
926       if (!powersave)
927         {
928           // Computer is going down
929           set_operation_mode_override( OPERATION_MODE_SUSPENDED, "powersave" );
930           powersave_resume_time = 0;
931           powersave = true;
932         }
933 
934       save_state();
935       statistics->update();
936     }
937   else
938     {
939       // Computer is coming back
940       // leave powersave true until the timewarp is detected
941       // or until some time has passed
942       if (powersave_resume_time == 0)
943         {
944           powersave_resume_time = current_time ? current_time : 1;
945           TRACE_MSG("set resume time " << powersave_resume_time);
946         }
947 
948       TRACE_MSG("resume time " << powersave_resume_time);
949       remove_operation_mode_override( "powersave" );
950     }
951   TRACE_EXIT();
952 }
953 
954 
955 //! Sets the insist policy.
956 /*!
957  *  The insist policy determines what to do when the user is active while
958  *  taking a break.
959  */
960 void
set_insist_policy(ICore::InsistPolicy p)961 Core::set_insist_policy(ICore::InsistPolicy p)
962 {
963   TRACE_ENTER_MSG("Core::set_insist_policy", p);
964 
965   if (active_insist_policy != ICore::INSIST_POLICY_INVALID &&
966       insist_policy != p)
967     {
968       TRACE_MSG("refreeze " << active_insist_policy);
969       defrost();
970       insist_policy = p;
971       freeze();
972     }
973   else
974     {
975       insist_policy = p;
976     }
977   TRACE_EXIT();
978 }
979 
980 
981 //! Gets the insist policy.
982 ICore::InsistPolicy
get_insist_policy() const983 Core::get_insist_policy() const
984 {
985   return insist_policy;
986 }
987 
988 
989 
990 // ! Forces all monitors to be idle.
991 void
force_idle()992 Core::force_idle()
993 {
994   TRACE_ENTER("Core::force_idle");
995   force_idle(BREAK_ID_NONE);
996   TRACE_EXIT();
997 }
998 
999 
1000 void
force_idle(BreakId break_id)1001 Core::force_idle(BreakId break_id)
1002 {
1003   TRACE_ENTER("Core::force_idle_for_break");
1004 
1005   monitor->force_idle();
1006 
1007   for (int i = 0; i < BREAK_ID_SIZEOF; i++)
1008     {
1009       if (break_id == BREAK_ID_NONE || i == break_id)
1010         {
1011           IActivityMonitor *am = breaks[i].get_timer()->get_activity_monitor();
1012           if (am != NULL)
1013             {
1014               am->force_idle();
1015             }
1016         }
1017 
1018       breaks[i].get_timer()->force_idle();
1019     }
1020   TRACE_EXIT();
1021 }
1022 
1023 
1024 /********************************************************************************/
1025 /**** Break Response                                                       ******/
1026 /********************************************************************************/
1027 
1028 //! User postpones the specified break.
1029 void
postpone_break(BreakId break_id)1030 Core::postpone_break(BreakId break_id)
1031 {
1032   do_postpone_break(break_id);
1033 
1034 #ifdef HAVE_DISTRIBUTION
1035   send_break_control_message(break_id, BCM_POSTPONE);
1036 #endif
1037 }
1038 
1039 
1040 //! User skips the specified break.
1041 void
skip_break(BreakId break_id)1042 Core::skip_break(BreakId break_id)
1043 {
1044   do_skip_break(break_id);
1045 
1046 #ifdef HAVE_DISTRIBUTION
1047   send_break_control_message(break_id, BCM_SKIP);
1048 #endif
1049 }
1050 
1051 
1052 //! User stops the prelude.
1053 void
stop_prelude(BreakId break_id)1054 Core::stop_prelude(BreakId break_id)
1055 {
1056   TRACE_ENTER_MSG("Core::stop_prelude", break_id);
1057   do_stop_prelude(break_id);
1058 
1059 #ifdef HAVE_DISTRIBUTION
1060   send_break_control_message(break_id, BCM_ABORT_PRELUDE);
1061 #endif
1062 
1063   TRACE_EXIT();
1064 }
1065 
1066 
1067 //! User postpones the specified break.
1068 void
do_postpone_break(BreakId break_id)1069 Core::do_postpone_break(BreakId break_id)
1070 {
1071   if (break_id >= 0 && break_id < BREAK_ID_SIZEOF)
1072     {
1073       BreakControl *bc = breaks[break_id].get_break_control();
1074       bc->postpone_break();
1075     }
1076 }
1077 
1078 
1079 //! User skips the specified break.
1080 void
do_skip_break(BreakId break_id)1081 Core::do_skip_break(BreakId break_id)
1082 {
1083   if (break_id >= 0 && break_id < BREAK_ID_SIZEOF)
1084     {
1085       BreakControl *bc = breaks[break_id].get_break_control();
1086       bc->skip_break();
1087     }
1088 }
1089 
1090 
1091 //!
1092 void
do_stop_prelude(BreakId break_id)1093 Core::do_stop_prelude(BreakId break_id)
1094 {
1095   TRACE_ENTER_MSG("Core::do_stop_prelude", break_id);
1096   if (break_id >= 0 && break_id < BREAK_ID_SIZEOF)
1097     {
1098       BreakControl *bc = breaks[break_id].get_break_control();
1099       bc->stop_prelude();
1100     }
1101   TRACE_EXIT();
1102 }
1103 
1104 
1105 /********************************************************************************/
1106 /**** Break handling                                                       ******/
1107 /********************************************************************************/
1108 
1109 //! Periodic heartbeat.
1110 void
heartbeat()1111 Core::heartbeat()
1112 {
1113   TRACE_ENTER("Core::heartbeat");
1114   assert(application != NULL);
1115 
1116   // Set current time.
1117   current_time = time(NULL);
1118 
1119   // Performs timewarp checking.
1120   bool warped = process_timewarp();
1121 
1122   // Process configuration
1123   configurator->heartbeat();
1124 
1125   // Perform distribution processing.
1126   process_distribution();
1127 
1128   if (!warped)
1129     {
1130       // Perform state computation.
1131       process_state();
1132     }
1133 
1134   // Perform timer processing.
1135   process_timers();
1136 
1137   // Send heartbeats to other components.
1138   for (int i = 0; i < BREAK_ID_SIZEOF; i++)
1139     {
1140       BreakControl *bc = breaks[i].get_break_control();
1141       if (bc != NULL && bc->need_heartbeat())
1142         {
1143           bc->heartbeat();
1144         }
1145     }
1146 
1147   // Make state persistent.
1148   if (current_time % SAVESTATETIME == 0)
1149     {
1150       statistics->update();
1151       save_state();
1152     }
1153 
1154   // Done.
1155   last_process_time = current_time;
1156 
1157   TRACE_EXIT();
1158 }
1159 
1160 
1161 //! Performs all distribution processing.
1162 void
process_distribution()1163 Core::process_distribution()
1164 {
1165   bool previous_master_mode = master_node;
1166 
1167   // Default
1168   master_node = true;
1169 
1170 #ifdef HAVE_DISTRIBUTION
1171 
1172   // Retrieve State.
1173   ActivityState state = monitor->get_current_state();
1174 
1175   if (dist_manager != NULL)
1176     {
1177       dist_manager->heartbeart();
1178       dist_manager->set_lock_master(state == ACTIVITY_ACTIVE);
1179       master_node = dist_manager->is_master();
1180 
1181       if (!master_node && state == ACTIVITY_ACTIVE)
1182         {
1183           master_node = dist_manager->claim();
1184         }
1185     }
1186 
1187   if ( (previous_master_mode != master_node) ||
1188        (master_node && local_state != state) )
1189     {
1190       PacketBuffer buffer;
1191       buffer.create();
1192 
1193       buffer.pack_ushort(1);
1194       buffer.pack_ushort(state);
1195 
1196       dist_manager->broadcast_client_message(DCM_MONITOR, buffer);
1197 
1198       buffer.clear();
1199       bool ret = request_timer_state(buffer);
1200       if (ret)
1201         {
1202           dist_manager->broadcast_client_message(DCM_TIMERS, buffer);
1203         }
1204     }
1205 
1206 #endif
1207 }
1208 
1209 
1210 //! Computes the current state.
1211 void
process_state()1212 Core::process_state()
1213 {
1214   // Default
1215   local_state = monitor->get_current_state();
1216 
1217   map<std::string, time_t>::iterator i = external_activity.begin();
1218   while (i != external_activity.end())
1219     {
1220       map<std::string, time_t>::iterator next = i;
1221       next++;
1222 
1223       if (i->second >= current_time)
1224         {
1225           local_state = ACTIVITY_ACTIVE;
1226         }
1227       else
1228         {
1229           external_activity.erase(i);
1230         }
1231 
1232       i = next;
1233     }
1234 
1235   monitor_state = local_state;
1236 
1237 #if defined(HAVE_DISTRIBUTION) && !defined(NDEBUG)
1238   if (fake_monitor != NULL)
1239     {
1240       monitor_state = fake_monitor->get_current_state();
1241     }
1242 #endif
1243 
1244 #ifdef HAVE_DISTRIBUTION
1245   if (!master_node)
1246     {
1247       if (active_insist_policy == INSIST_POLICY_IGNORE)
1248         {
1249           // Our own monitor is suspended, also ignore
1250           // activity from remote parties.
1251           monitor_state = ACTIVITY_IDLE;
1252         }
1253       else
1254         {
1255           monitor_state = remote_state;
1256         }
1257     }
1258 
1259   // Update our idle history.
1260   idlelog_manager->update_all_idlelogs(dist_manager->get_master_id(), monitor_state);
1261 #endif
1262 }
1263 
1264 
1265 void
report_external_activity(std::string who,bool act)1266 Core::report_external_activity(std::string who, bool act)
1267 {
1268   TRACE_ENTER_MSG("Core::report_external_activity", who << " " << act);
1269   if (act)
1270     {
1271       external_activity[who] = current_time + 10;
1272     }
1273   else
1274     {
1275       external_activity.erase(who);
1276     }
1277   TRACE_EXIT();
1278 }
1279 
1280 
1281 void
is_timer_running(BreakId id,bool & value)1282 Core::is_timer_running(BreakId id, bool &value)
1283 {
1284   Timer *timer = get_timer(id);
1285   value = timer->get_state() == STATE_RUNNING;
1286 }
1287 
1288 
1289 void
get_timer_idle(BreakId id,int * value)1290 Core::get_timer_idle(BreakId id, int *value)
1291 {
1292   Timer *timer = get_timer(id);
1293   *value = (int) timer->get_elapsed_idle_time();
1294 }
1295 
1296 
1297 void
get_timer_elapsed(BreakId id,int * value)1298 Core::get_timer_elapsed(BreakId id, int *value)
1299 {
1300   Timer *timer = get_timer(id);
1301   *value = (int) timer->get_elapsed_time();
1302 }
1303 
1304 
1305 void
get_timer_remaining(BreakId id,int * value)1306 Core::get_timer_remaining(BreakId id, int *value)
1307 {
1308   Timer *timer = get_timer(id);
1309 
1310   *value = -1;
1311 
1312   if (timer->is_limit_enabled())
1313     {
1314       int remaining = timer->get_limit() - timer->get_elapsed_time();
1315       *value = remaining >= 0 ? remaining : 0;
1316     }
1317 }
1318 
1319 
1320 void
get_timer_overdue(BreakId id,int * value)1321 Core::get_timer_overdue(BreakId id, int *value)
1322 {
1323   Timer *timer = get_timer(id);
1324   *value = (int) timer->get_total_overdue_time();
1325 }
1326 
1327 //! Processes all timers.
1328 void
process_timers()1329 Core::process_timers()
1330 {
1331   TRACE_ENTER("Core::process_timers");
1332 
1333   TimerInfo infos[BREAK_ID_SIZEOF];
1334 
1335   for (int i = 0; i < BREAK_ID_SIZEOF; i++)
1336     {
1337       Timer *timer = breaks[i].get_timer();
1338 
1339       infos[i].enabled = breaks[i].is_enabled();
1340       if (infos[i].enabled)
1341         {
1342           timer->enable();
1343           if (i == BREAK_ID_DAILY_LIMIT)
1344             {
1345               timer->set_limit_enabled(timer->get_limit() > 0);
1346             }
1347         }
1348       else
1349         {
1350           if (i != BREAK_ID_DAILY_LIMIT)
1351             {
1352               timer->disable();
1353             }
1354           else
1355             {
1356               timer->set_limit_enabled(false);
1357             }
1358         }
1359 
1360       // First process only timer that do not have their
1361       // own activity monitor.
1362       if (!(timer->has_activity_monitor()))
1363         {
1364           timer->process(monitor_state, infos[i]);
1365         }
1366     }
1367 
1368   // And process timer with activity monitor.
1369   for (int i = 0; i < BREAK_ID_SIZEOF; i++)
1370     {
1371       if (breaks[i].get_timer()->has_activity_monitor())
1372         {
1373           breaks[i].get_timer()->process(monitor_state, infos[i]);
1374         }
1375     }
1376 
1377 
1378   // Process all timer events.
1379   for (int i = BREAK_ID_SIZEOF - 1; i >= 0;  i--)
1380     {
1381       TimerInfo &info = infos[i];
1382       if (breaks[i].is_enabled())
1383         {
1384           timer_action((BreakId)i, info);
1385         }
1386 
1387       if (i == BREAK_ID_DAILY_LIMIT &&
1388           (info.event == TIMER_EVENT_NATURAL_RESET ||
1389            info.event == TIMER_EVENT_RESET))
1390         {
1391           statistics->set_counter(Statistics::STATS_VALUE_TOTAL_ACTIVE_TIME, (int) info.elapsed_time);
1392           statistics->start_new_day();
1393 
1394           daily_reset();
1395         }
1396     }
1397 
1398   TRACE_EXIT();
1399 }
1400 
1401 #if defined(PLATFORM_OS_WIN32)
1402 
1403 //! Process a possible timewarp on Win32
1404 bool
process_timewarp()1405 Core::process_timewarp()
1406 {
1407   bool ret = false;
1408 
1409   TRACE_ENTER("Core::process_timewarp");
1410   if (last_process_time != 0)
1411     {
1412       time_t gap = current_time - 1 - last_process_time;
1413 
1414       if (abs((int)gap) > 5)
1415         {
1416           TRACE_MSG("gap " << gap << " " << powersave << " " << operation_mode << " " << powersave_resume_time << " " << current_time);
1417 
1418           if (!powersave)
1419             {
1420               TRACE_MSG("Time warp of " << gap << " seconds. Correcting");
1421 
1422               force_idle();
1423 
1424               monitor->shift_time((int)gap);
1425               for (int i = 0; i < BREAK_ID_SIZEOF; i++)
1426                 {
1427                   breaks[i].get_timer()->shift_time((int)gap);
1428                 }
1429 
1430               monitor_state = ACTIVITY_IDLE;
1431               ret = true;
1432             }
1433           else
1434             {
1435               TRACE_MSG("Time warp of " << gap << " seconds because of powersave");
1436 
1437               // In case the windows message was lost. some people reported that
1438               // workrave never restarted the timers...
1439               remove_operation_mode_override( "powersave" );
1440             }
1441         }
1442 
1443       if (powersave && powersave_resume_time != 0 && current_time > powersave_resume_time + 30)
1444         {
1445           TRACE_MSG("End of time warp after powersave");
1446 
1447           powersave = false;
1448           powersave_resume_time = 0;
1449         }
1450     }
1451   TRACE_EXIT();
1452   return ret;
1453 }
1454 
1455 #else
1456 
1457 //! Process a possible timewarp On Non-Windows
1458 bool
process_timewarp()1459 Core::process_timewarp()
1460 {
1461   bool ret = false;
1462 
1463   TRACE_ENTER("Core::process_timewarp");
1464   if (last_process_time != 0)
1465     {
1466       int gap = current_time - 1 - last_process_time;
1467 
1468       if (gap >= 30)
1469         {
1470           TRACE_MSG("Time warp of " << gap << " seconds. Powersafe");
1471 
1472           force_idle();
1473 
1474           int save_current_time = current_time;
1475 
1476           current_time = last_process_time + 1;
1477           monitor_state = ACTIVITY_IDLE;
1478 
1479           process_timers();
1480 
1481           current_time = save_current_time;
1482           ret = true;
1483         }
1484     }
1485 
1486   TRACE_EXIT();
1487   return ret;
1488 }
1489 
1490 #endif
1491 
1492 //! Notication of a timer action.
1493 /*!
1494  *  \param timerId ID of the timer that caused the action.
1495  *  \param action action that is performed by the timer.
1496 */
1497 void
timer_action(BreakId id,TimerInfo info)1498 Core::timer_action(BreakId id, TimerInfo info)
1499 {
1500   // No breaks when mode is quiet,
1501   if (operation_mode == OPERATION_MODE_QUIET &&
1502       info.event == TIMER_EVENT_LIMIT_REACHED)
1503     {
1504       return;
1505     }
1506 
1507   BreakControl *breaker = breaks[id].get_break_control();
1508   Timer *timer = breaks[id].get_timer();
1509 
1510   assert(breaker != NULL && timer != NULL);
1511 
1512   switch (info.event)
1513     {
1514     case TIMER_EVENT_LIMIT_REACHED:
1515       if (breaker->get_break_state() == BreakControl::BREAK_INACTIVE)
1516         {
1517           start_break(id);
1518         }
1519       break;
1520 
1521     case TIMER_EVENT_NATURAL_RESET:
1522       statistics->increment_break_counter(id, Statistics::STATS_BREAKVALUE_NATURAL_TAKEN);
1523       // FALLTHROUGH
1524 
1525     case TIMER_EVENT_RESET:
1526       if (breaker->get_break_state() == BreakControl::BREAK_ACTIVE)
1527         {
1528           breaker->stop_break();
1529         }
1530       break;
1531 
1532     default:
1533       break;
1534     }
1535 }
1536 
1537 
1538 //! starts the specified break.
1539 /*!
1540  *  \param break_id ID of the timer that caused the break.
1541  */
1542 void
start_break(BreakId break_id,BreakId resume_this_break)1543 Core::start_break(BreakId break_id, BreakId resume_this_break)
1544 {
1545   // Don't show MB when RB is active, RB when DL is active.
1546   for (int bi = break_id; bi <= BREAK_ID_DAILY_LIMIT; bi++)
1547     {
1548       if (breaks[bi].get_break_control()->get_break_state() == BreakControl::BREAK_ACTIVE)
1549         {
1550           return;
1551         }
1552     }
1553 
1554   // Advance restbreak if it follows within 30s after the end of a microbreak
1555   if (break_id == BREAK_ID_REST_BREAK && resume_this_break == BREAK_ID_NONE)
1556     {
1557       breaks[BREAK_ID_REST_BREAK].override(BREAK_ID_REST_BREAK);
1558     }
1559 
1560   if (break_id == BREAK_ID_MICRO_BREAK && breaks[BREAK_ID_REST_BREAK].is_enabled())
1561     {
1562       Timer *rb_timer = breaks[BREAK_ID_REST_BREAK].get_timer();
1563       assert(rb_timer != NULL);
1564 
1565       bool activity_sensitive = breaks[BREAK_ID_REST_BREAK].get_timer_activity_sensitive();
1566 
1567       // Only advance when
1568       // 0. It is activity sensitive
1569       // 1. we have a next limit reached time.
1570       if (activity_sensitive &&
1571           rb_timer->get_next_limit_time() > 0)
1572         {
1573           Timer *timer = breaks[break_id].get_timer();
1574 
1575           time_t duration = timer->get_auto_reset();
1576           time_t now = get_time();
1577 
1578           if (now + duration + 30 >= rb_timer->get_next_limit_time())
1579             {
1580               breaks[BREAK_ID_REST_BREAK].override(BREAK_ID_MICRO_BREAK);
1581 
1582               start_break(BREAK_ID_REST_BREAK, BREAK_ID_MICRO_BREAK);
1583 
1584               // Snooze timer before the limit was reached. Just to make sure
1585               // that it doesn't reach its limit again when elapsed == limit
1586               rb_timer->snooze_timer();
1587               return;
1588             }
1589         }
1590     }
1591 
1592   // Stop microbreak when a restbreak starts. should not happend.
1593   // restbreak should be advanced.
1594   for (int bi = BREAK_ID_MICRO_BREAK; bi < break_id; bi++)
1595     {
1596       if (breaks[bi].get_break_control()->get_break_state() == BreakControl::BREAK_ACTIVE)
1597         {
1598           breaks[bi].get_break_control()->stop_break(false);
1599         }
1600     }
1601 
1602   // If break 'break_id' ends, and break 'resume_this_break' is still
1603   // active, resume it...
1604   resume_break = resume_this_break;
1605 
1606   BreakControl *breaker = breaks[break_id].get_break_control();
1607   breaker->start_break();
1608 }
1609 
1610 
1611 //! Sets the freeze state of all breaks.
1612 void
set_freeze_all_breaks(bool freeze)1613 Core::set_freeze_all_breaks(bool freeze)
1614 {
1615   for (int i = 0; i < BREAK_ID_SIZEOF; i++)
1616     {
1617       Timer *t = breaks[i].get_timer();
1618       assert(t != NULL);
1619       if (!t->has_activity_monitor())
1620         {
1621           t->freeze_timer(freeze);
1622         }
1623     }
1624 }
1625 
1626 void
set_insensitive_mode_all_breaks(InsensitiveMode mode)1627 Core::set_insensitive_mode_all_breaks(InsensitiveMode mode)
1628 {
1629   for (int i = 0; i < BREAK_ID_SIZEOF; i++)
1630     {
1631       Timer *t = breaks[i].get_timer();
1632       assert(t != NULL);
1633       t->set_insensitive_mode(mode);
1634     }
1635 }
1636 
1637 
1638 //! Stops all breaks.
1639 void
stop_all_breaks()1640 Core::stop_all_breaks()
1641 {
1642   for (int i = 0; i < BREAK_ID_SIZEOF; i++)
1643     {
1644       BreakControl *bc = breaks[i].get_break_control();
1645       assert(bc != NULL);
1646       bc->stop_break(false);
1647     }
1648 }
1649 
1650 
1651 /********************************************************************************/
1652 /**** Misc                                                                 ******/
1653 /********************************************************************************/
1654 
1655 //! Performs a reset when the daily limit is reached.
1656 void
daily_reset()1657 Core::daily_reset()
1658 {
1659   TRACE_ENTER("Core::daily_reset");
1660   for (int i = 0; i < BREAK_ID_SIZEOF; i++)
1661     {
1662       Timer *t = breaks[i].get_timer();
1663       assert(t != NULL);
1664 
1665       time_t overdue = t->get_total_overdue_time();
1666 
1667       statistics->set_break_counter(((BreakId)i),
1668                                     Statistics::STATS_BREAKVALUE_TOTAL_OVERDUE, (int)overdue);
1669 
1670       t->daily_reset_timer();
1671     }
1672 
1673 
1674 #ifdef HAVE_DISTRIBUTION
1675   idlelog_manager->reset();
1676 #endif
1677 
1678   save_state();
1679 
1680   TRACE_EXIT();
1681 }
1682 
1683 
1684 //! Saves the current state.
1685 void
save_state() const1686 Core::save_state() const
1687 {
1688   stringstream ss;
1689   ss << Util::get_home_directory();
1690   ss << "state" << ends;
1691 
1692   ofstream stateFile(ss.str().c_str());
1693 
1694   stateFile << "WorkRaveState 3"  << endl
1695             << get_time() << endl;
1696 
1697   for (int i = 0; i < BREAK_ID_SIZEOF; i++)
1698     {
1699       string stateStr = breaks[i].get_timer()->serialize_state();
1700 
1701       stateFile << stateStr << endl;
1702     }
1703 
1704   stateFile.close();
1705 }
1706 
1707 
1708 //! Loads miscellaneous
1709 void
load_misc()1710 Core::load_misc()
1711 {
1712   configurator->rename_key("gui/operation-mode", CoreConfig::CFG_KEY_OPERATION_MODE);
1713   configurator->add_listener(CoreConfig::CFG_KEY_OPERATION_MODE, this);
1714   configurator->add_listener(CoreConfig::CFG_KEY_USAGE_MODE, this);
1715 
1716   int mode;
1717   if (! get_configurator()->get_value(CoreConfig::CFG_KEY_OPERATION_MODE, mode))
1718     {
1719       mode = OPERATION_MODE_NORMAL;
1720     }
1721   set_operation_mode(OperationMode(mode));
1722 
1723   if (! get_configurator()->get_value(CoreConfig::CFG_KEY_USAGE_MODE, mode))
1724     {
1725       mode = USAGE_MODE_NORMAL;
1726     }
1727   set_usage_mode(UsageMode(mode));
1728 }
1729 
1730 
1731 //! Loads the current state.
1732 void
load_state()1733 Core::load_state()
1734 {
1735   stringstream ss;
1736   ss << Util::get_home_directory();
1737   ss << "state" << ends;
1738 
1739   ifstream stateFile(ss.str().c_str());
1740 
1741   int version = 0;
1742   bool ok = stateFile.good();
1743 
1744   if (ok)
1745     {
1746       string tag;
1747       stateFile >> tag;
1748 
1749       ok = (tag == WORKRAVESTATE);
1750     }
1751 
1752   if (ok)
1753     {
1754       stateFile >> version;
1755 
1756       ok = (version >= 1 && version <= 3);
1757     }
1758 
1759   if (ok)
1760     {
1761       time_t saveTime;
1762       stateFile >> saveTime;
1763     }
1764 
1765   while (ok && !stateFile.eof())
1766     {
1767       string id;
1768       stateFile >> id;
1769 
1770       for (int i = 0; i < BREAK_ID_SIZEOF; i++)
1771         {
1772           if (breaks[i].get_timer()->get_id() == id)
1773             {
1774               string state;
1775               getline(stateFile, state);
1776 
1777               breaks[i].get_timer()->deserialize_state(state, version);
1778               break;
1779             }
1780         }
1781     }
1782 }
1783 
1784 
1785 //! Post an event.
1786 void
post_event(CoreEvent event)1787 Core::post_event(CoreEvent event)
1788 {
1789   if (core_event_listener != NULL)
1790     {
1791       core_event_listener->core_event_notify(event);
1792     }
1793 }
1794 
1795 
1796 //! Excecute the insist policy.
1797 void
freeze()1798 Core::freeze()
1799 {
1800   TRACE_ENTER_MSG("Core::freeze", insist_policy);
1801   ICore::InsistPolicy policy = insist_policy;
1802 
1803   switch (policy)
1804     {
1805     case ICore::INSIST_POLICY_IGNORE:
1806       {
1807         // Ignore all activity during break by suspending the activity monitor.
1808         monitor->suspend();
1809       }
1810       break;
1811     case ICore::INSIST_POLICY_HALT:
1812       {
1813         // Halt timer when the user is active.
1814         set_freeze_all_breaks(true);
1815       }
1816       break;
1817     case ICore::INSIST_POLICY_RESET:
1818       // reset the timer when the user becomes active.
1819       // default.
1820       break;
1821 
1822     default:
1823       break;
1824     }
1825 
1826   active_insist_policy = policy;
1827   TRACE_EXIT();
1828 }
1829 
1830 
1831 //! Undo the insist policy.
1832 void
defrost()1833 Core::defrost()
1834 {
1835   TRACE_ENTER_MSG("Core::defrost", active_insist_policy);
1836 
1837   switch (active_insist_policy)
1838     {
1839     case ICore::INSIST_POLICY_IGNORE:
1840       {
1841         // Resumes the activity monitor, if not suspended.
1842         if (operation_mode != OPERATION_MODE_SUSPENDED)
1843           {
1844             monitor->resume();
1845           }
1846       }
1847       break;
1848     case ICore::INSIST_POLICY_HALT:
1849       {
1850         // Desfrost timers.
1851         set_freeze_all_breaks(false);
1852       }
1853       break;
1854 
1855     default:
1856       break;
1857     }
1858 
1859   active_insist_policy = ICore::INSIST_POLICY_INVALID;
1860   TRACE_EXIT();
1861 }
1862 
1863 
1864 //! Is the user currently active?
1865 bool
is_user_active() const1866 Core::is_user_active() const
1867 {
1868   return monitor_state == ACTIVITY_ACTIVE;
1869 }
1870 
1871 
1872 /********************************************************************************/
1873 /**** Distribution                                                         ******/
1874 /********************************************************************************/
1875 
1876 #ifdef HAVE_DISTRIBUTION
1877 //! The distribution manager requests a client message.
1878 bool
request_client_message(DistributionClientMessageID id,PacketBuffer & buffer)1879 Core::request_client_message(DistributionClientMessageID id, PacketBuffer &buffer)
1880 {
1881   bool ret = false;
1882 
1883   switch (id)
1884     {
1885     case DCM_BREAKS:
1886       ret = request_break_state(buffer);
1887       break;
1888 
1889     case DCM_TIMERS:
1890       ret = request_timer_state(buffer);
1891       break;
1892 
1893     case DCM_CONFIG:
1894       break;
1895 
1896     case DCM_MONITOR:
1897       ret = true;
1898       break;
1899 
1900     case DCM_BREAKCONTROL:
1901       ret = true;
1902       break;
1903 
1904     case DCM_IDLELOG:
1905       idlelog_manager->get_idlelog(buffer);
1906       ret = true;
1907       break;
1908 
1909     default:
1910       break;
1911     }
1912 
1913   return ret;
1914 }
1915 
1916 
1917 //! The distribution manager delivers a client message.
1918 bool
client_message(DistributionClientMessageID id,bool master,const char * client_id,PacketBuffer & buffer)1919 Core::client_message(DistributionClientMessageID id, bool master, const char *client_id,
1920                      PacketBuffer &buffer)
1921 {
1922   bool ret = false;
1923 
1924   (void) client_id;
1925 
1926   switch (id)
1927     {
1928     case DCM_BREAKS:
1929       ret = set_break_state(master, buffer);
1930       break;
1931 
1932     case DCM_TIMERS:
1933       ret = set_timer_state(buffer);
1934       break;
1935 
1936     case DCM_MONITOR:
1937       ret = set_monitor_state(master, buffer);
1938       break;
1939 
1940     case DCM_BREAKCONTROL:
1941       ret = set_break_control(buffer);
1942       break;
1943 
1944     case DCM_CONFIG:
1945       break;
1946 
1947     case DCM_IDLELOG:
1948       idlelog_manager->set_idlelog(buffer);
1949       compute_timers();
1950       ret = true;
1951       break;
1952 
1953     default:
1954       break;
1955     }
1956 
1957   return ret;
1958 }
1959 
1960 
1961 bool
request_break_state(PacketBuffer & buffer)1962 Core::request_break_state(PacketBuffer &buffer)
1963 {
1964   buffer.pack_ushort(BREAK_ID_SIZEOF);
1965 
1966   for (int i = 0; i < BREAK_ID_SIZEOF; i++)
1967     {
1968       BreakControl *bi = breaks[i].get_break_control();
1969 
1970       if (bi != NULL)
1971         {
1972           BreakControl::BreakStateData state_data;
1973           bi->get_state_data(state_data);
1974 
1975           int pos = buffer.bytes_written();
1976 
1977           buffer.pack_ushort(0);
1978           buffer.pack_byte((guint8)state_data.forced_break);
1979           buffer.pack_byte((guint8)state_data.reached_max_prelude);
1980           buffer.pack_ulong((guint32)state_data.prelude_count);
1981           buffer.pack_ulong((guint32)state_data.break_stage);
1982           buffer.pack_ulong((guint32)state_data.prelude_time);
1983 
1984           buffer.poke_ushort(pos, buffer.bytes_written() - pos);
1985         }
1986       else
1987         {
1988           buffer.pack_ushort(0);
1989         }
1990     }
1991 
1992   return true;
1993 }
1994 
1995 
1996 bool
set_break_state(bool master,PacketBuffer & buffer)1997 Core::set_break_state(bool master, PacketBuffer &buffer)
1998 {
1999   int num_breaks = buffer.unpack_ushort();
2000 
2001   if (num_breaks > BREAK_ID_SIZEOF)
2002     {
2003       num_breaks = BREAK_ID_SIZEOF;
2004     }
2005 
2006   for (int i = 0; i < num_breaks; i++)
2007     {
2008       BreakControl *bi = breaks[i].get_break_control();
2009 
2010       BreakControl::BreakStateData state_data;
2011 
2012       int data_size = buffer.unpack_ushort();
2013 
2014       if (data_size > 0)
2015         {
2016           state_data.forced_break = buffer.unpack_byte();
2017           state_data.reached_max_prelude = buffer.unpack_byte();
2018           state_data.prelude_count = buffer.unpack_ulong();
2019           state_data.break_stage = buffer.unpack_ulong();
2020           state_data.prelude_time = buffer.unpack_ulong();
2021 
2022           bi->set_state_data(master, state_data);
2023         }
2024     }
2025 
2026   return true;
2027 }
2028 
2029 bool
request_timer_state(PacketBuffer & buffer) const2030 Core::request_timer_state(PacketBuffer &buffer) const
2031 {
2032   TRACE_ENTER("Core::get_timer_state");
2033 
2034   buffer.pack_ushort(BREAK_ID_SIZEOF);
2035 
2036   for (int i = 0; i < BREAK_ID_SIZEOF; i++)
2037     {
2038       Timer *t = breaks[i].get_timer();
2039       buffer.pack_string(t->get_id().c_str());
2040 
2041       Timer::TimerStateData state_data;
2042 
2043       t->get_state_data(state_data);
2044 
2045       int pos = buffer.bytes_written();
2046 
2047       buffer.pack_ushort(0);
2048       buffer.pack_ulong((guint32)state_data.current_time);
2049       buffer.pack_ulong((guint32)state_data.elapsed_time);
2050       buffer.pack_ulong((guint32)state_data.elapsed_idle_time);
2051       buffer.pack_ulong((guint32)state_data.last_pred_reset_time);
2052       buffer.pack_ulong((guint32)state_data.total_overdue_time);
2053 
2054       buffer.pack_ulong((guint32)state_data.last_limit_time);
2055       buffer.pack_ulong((guint32)state_data.last_limit_elapsed);
2056       buffer.pack_ushort((guint16)state_data.snooze_inhibited);
2057 
2058       buffer.poke_ushort(pos, buffer.bytes_written() - pos);
2059     }
2060 
2061   TRACE_EXIT();
2062   return true;
2063 }
2064 
2065 
2066 bool
set_timer_state(PacketBuffer & buffer)2067 Core::set_timer_state(PacketBuffer &buffer)
2068 {
2069   TRACE_ENTER("Core::set_timer_state");
2070 
2071   int num_breaks = buffer.unpack_ushort();
2072 
2073   TRACE_MSG("numtimer = " << num_breaks);
2074   for (int i = 0; i < num_breaks; i++)
2075     {
2076       gchar *id = buffer.unpack_string();
2077       TRACE_MSG("id = " << id);
2078 
2079       if (id == NULL)
2080         {
2081           TRACE_EXIT();
2082           return false;
2083         }
2084 
2085       Timer *t = (Timer *)get_timer(id);
2086 
2087       Timer::TimerStateData state_data;
2088 
2089       buffer.unpack_ushort();
2090 
2091       state_data.current_time = buffer.unpack_ulong();
2092       state_data.elapsed_time = buffer.unpack_ulong();
2093       state_data.elapsed_idle_time = buffer.unpack_ulong();
2094       state_data.last_pred_reset_time = buffer.unpack_ulong();
2095       state_data.total_overdue_time = buffer.unpack_ulong();
2096 
2097       state_data.last_limit_time = buffer.unpack_ulong();
2098       state_data.last_limit_elapsed = buffer.unpack_ulong();
2099       state_data.snooze_inhibited = buffer.unpack_ushort();
2100 
2101       TRACE_MSG("state = "
2102                 << state_data.current_time << " "
2103                 << state_data.elapsed_time << " "
2104                 << state_data.elapsed_idle_time << " "
2105                 << state_data.last_pred_reset_time << " "
2106                 << state_data.total_overdue_time
2107                 );
2108 
2109       if (t != NULL)
2110         {
2111           t->set_state_data(state_data);
2112         }
2113 
2114       g_free(id);
2115     }
2116 
2117   TRACE_EXIT();
2118   return true;
2119 }
2120 
2121 
2122 bool
set_monitor_state(bool master,PacketBuffer & buffer)2123 Core::set_monitor_state(bool master, PacketBuffer &buffer)
2124 {
2125   (void) master;
2126   TRACE_ENTER_MSG("Core::set_monitor_state", master << " " << master_node);
2127 
2128   if (!master_node)
2129     {
2130       buffer.unpack_ushort();
2131       remote_state = (ActivityState) buffer.unpack_ushort();
2132       TRACE_MSG(remote_state);
2133     }
2134 
2135   TRACE_EXIT();
2136   return true;
2137 }
2138 
2139 
2140 //! A remote client has signed on.
2141 void
signon_remote_client(string client_id)2142 Core::signon_remote_client(string client_id)
2143 {
2144   idlelog_manager->signon_remote_client(client_id);
2145 
2146   if (master_node)
2147     {
2148       PacketBuffer buffer;
2149       buffer.create();
2150 
2151       ActivityState state = monitor->get_current_state();
2152 
2153       buffer.pack_ushort(1);
2154       buffer.pack_ushort(state);
2155 
2156       dist_manager->broadcast_client_message(DCM_MONITOR, buffer);
2157 
2158       buffer.clear();
2159     }
2160 }
2161 
2162 
2163 //! A remote client has signed off.
2164 void
signoff_remote_client(string client_id)2165 Core::signoff_remote_client(string client_id)
2166 {
2167   TRACE_ENTER_MSG("Core::signoff_remote_client", client_id);
2168   TRACE_MSG("Master = " << dist_manager->get_master_id());
2169   if (client_id == dist_manager->get_master_id())
2170     {
2171       TRACE_MSG("Idle");
2172       remote_state = ACTIVITY_IDLE;
2173     }
2174 
2175   idlelog_manager->signoff_remote_client(client_id);
2176   TRACE_EXIT();
2177 }
2178 
2179 
2180 void
compute_timers()2181 Core::compute_timers()
2182 {
2183   TRACE_ENTER("IdleLogManager:compute_timers");
2184 
2185   for (int i = 0; i < BREAK_ID_SIZEOF; i++)
2186     {
2187       int autoreset = breaks[i].get_timer()->get_auto_reset();
2188       int idle = idlelog_manager->compute_idle_time();
2189 
2190       if (autoreset != 0)
2191         {
2192           int active_time = idlelog_manager->compute_active_time(autoreset);
2193 
2194           if (idle > autoreset)
2195             {
2196               idle = autoreset;
2197             }
2198 
2199           breaks[i].get_timer()->set_values(active_time, idle);
2200         }
2201       else
2202         {
2203           int active_time = idlelog_manager->compute_total_active_time();
2204           breaks[i].get_timer()->set_values(active_time, idle);
2205         }
2206     }
2207 
2208   TRACE_EXIT();
2209 }
2210 
2211 
2212 //! Sends a break control message to all workrave clients.
2213 void
send_break_control_message(BreakId break_id,BreakControlMessage message)2214 Core::send_break_control_message(BreakId break_id, BreakControlMessage message)
2215 {
2216   PacketBuffer buffer;
2217   buffer.create();
2218 
2219   buffer.pack_ushort(4);
2220   buffer.pack_ushort(break_id);
2221   buffer.pack_ushort(message);
2222 
2223   dist_manager->broadcast_client_message(DCM_BREAKCONTROL, buffer);
2224 }
2225 
2226 //! Sends a break control message with boolean parameter to all workrave clients.
2227 void
send_break_control_message_bool_param(BreakId break_id,BreakControlMessage message,bool param)2228 Core::send_break_control_message_bool_param(BreakId break_id, BreakControlMessage message,
2229                                             bool param)
2230 {
2231   PacketBuffer buffer;
2232   buffer.create();
2233 
2234   buffer.pack_ushort(5);
2235   buffer.pack_ushort(break_id);
2236   buffer.pack_ushort(message);
2237   buffer.pack_byte(param);
2238 
2239   dist_manager->broadcast_client_message(DCM_BREAKCONTROL, buffer);
2240 }
2241 
2242 
2243 bool
set_break_control(PacketBuffer & buffer)2244 Core::set_break_control(PacketBuffer &buffer)
2245 {
2246   int data_size = buffer.unpack_ushort();
2247 
2248   if (data_size >= 4)
2249     {
2250       BreakId break_id = (BreakId) buffer.unpack_ushort();
2251       BreakControlMessage message = (BreakControlMessage) buffer.unpack_ushort();
2252 
2253       switch (message)
2254         {
2255         case BCM_POSTPONE:
2256           do_postpone_break(break_id);
2257           break;
2258 
2259         case BCM_SKIP:
2260           do_skip_break(break_id);
2261           break;
2262 
2263         case BCM_ABORT_PRELUDE:
2264           do_stop_prelude(break_id);
2265           break;
2266 
2267         case BCM_START_BREAK:
2268           if (data_size >= 6)
2269             {
2270               // Only for post 1.9.1 workrave...
2271               int break_hint = (int) buffer.unpack_ushort();
2272               do_force_break(break_id, (BreakHint) break_hint);
2273             }
2274           else if (data_size >= 5)
2275             {
2276               // Only for post 1.6.2 workrave...
2277               bool initiated_by_user = (bool) buffer.unpack_byte();
2278               do_force_break(break_id, initiated_by_user ? BREAK_HINT_USER_INITIATED : BREAK_HINT_NONE);
2279             }
2280           else
2281             {
2282               do_force_break(break_id, BREAK_HINT_USER_INITIATED);
2283             }
2284           break;
2285         }
2286     }
2287 
2288   return true;
2289 }
2290 
2291 #endif // HAVE_DISTRIBUTION
2292 
2293 namespace workrave
2294 {
operator %(const string & key,BreakId id)2295   std::string operator%(const string &key, BreakId id)
2296   {
2297     IBreak *b = Core::get_instance()->get_break(id);
2298 
2299     string str = key;
2300     string::size_type pos = 0;
2301     string name = b->get_name();
2302 
2303     while ((pos = str.find("%b", pos)) != string::npos)
2304       {
2305         str.replace(pos, 2, name);
2306         pos++;
2307       }
2308 
2309     return str;
2310   }
2311 }
2312