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