1 /*
2  * Copyright (C) 2019-2020 Alexandros Theodotou <alex at zrythm dot org>
3  *
4  * This file is part of Zrythm
5  *
6  * Zrythm is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU Affero 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  * Zrythm 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 Affero General Public License for more details.
15  *
16  * You should have received a copy of the GNU Affero General Public License
17  * along with Zrythm.  If not, see <https://www.gnu.org/licenses/>.
18  */
19 
20 /**
21  * \file
22  *
23  * Events for calling refresh on widgets.
24  *
25  * Note: This is only for refreshing widgets. No
26  * logic should be performed here. Any logic must be
27  * done before pushing an event.
28  */
29 #ifndef __GUI_BACKEND_EVENT_MANAGER_H__
30 #define __GUI_BACKEND_EVENT_MANAGER_H__
31 
32 #include "utils/backtrace.h"
33 #include "utils/mpmc_queue.h"
34 #include "utils/object_pool.h"
35 
36 typedef struct Zrythm Zrythm;
37 typedef struct ZEvent ZEvent;
38 
39 /**
40  * @addtogroup events
41  *
42  * @{
43  */
44 
45 /**
46  * Event manager.
47  */
48 typedef struct EventManager
49 {
50   /**
51    * Event queue, mainly for GUI events.
52    */
53   MPMCQueue *        mqueue;
54 
55   /**
56    * Object pool of event structs to avoid real time
57    * allocation.
58    */
59   ObjectPool *       obj_pool;
60 
61   /** ID of the event processing source func. */
62   guint              process_source_id;
63 
64   /** A soft recalculation of the routing graph
65    * is pending. */
66   bool               pending_soft_recalc;
67 
68   /** Events array to use during processing. */
69   GPtrArray *        events_arr;
70 } EventManager;
71 
72 #define EVENT_MANAGER (ZRYTHM->event_manager)
73 
74 /** The event queue. */
75 #define EVENT_QUEUE (EVENT_MANAGER->mqueue)
76 
77 #define EVENT_MANAGER_MAX_EVENTS 4000
78 
79 #define event_queue_push_back_event(q,x) \
80   mpmc_queue_push_back (q, (void *) x)
81 
82 #define event_queue_dequeue_event(q,x) \
83   mpmc_queue_dequeue (q, (void *) x)
84 
85 /**
86  * Push events.
87  */
88 #define EVENTS_PUSH(et,_arg) \
89   if (ZRYTHM_HAVE_UI && EVENT_MANAGER && \
90       EVENT_QUEUE && \
91       (!PROJECT || !AUDIO_ENGINE || \
92        !AUDIO_ENGINE->exporting)) \
93     { \
94       ZEvent * _ev = \
95         (ZEvent *) \
96         object_pool_get (EVENT_MANAGER->obj_pool); \
97       _ev->file = __FILE__; \
98       _ev->func = __func__; \
99       _ev->lineno = __LINE__; \
100       _ev->type = (et); \
101       _ev->arg = (void *) (_arg); \
102       if (zrythm_app->gtk_thread == \
103             g_thread_self ()  \
104           /* skip backtrace for now */ \
105           && false) \
106         { \
107           _ev->backtrace = \
108             backtrace_get ("", 40, false); \
109         } \
110       /* don't print events that are called \
111        * continuously */ \
112       if ((et) != ET_PLAYHEAD_POS_CHANGED && \
113             g_thread_self () == \
114               zrythm_app->gtk_thread) \
115         { \
116           g_debug ( \
117             "pushing UI event " #et \
118             " (%s:%d)", __func__, __LINE__); \
119         } \
120       event_queue_push_back_event ( \
121         EVENT_QUEUE, _ev); \
122     }
123 
124 /* runs the event logic now */
125 #define EVENTS_PUSH_NOW(et,_arg) \
126   if (ZRYTHM_HAVE_UI && EVENT_MANAGER \
127       && EVENT_QUEUE \
128       && zrythm_app->gtk_thread \
129         == g_thread_self () \
130       && (!PROJECT || !AUDIO_ENGINE || \
131           !AUDIO_ENGINE->exporting)) \
132     { \
133       ZEvent * _ev = \
134         (ZEvent *) \
135         object_pool_get (EVENT_MANAGER->obj_pool); \
136       _ev->file = __FILE__; \
137       _ev->func = __func__; \
138       _ev->lineno = __LINE__; \
139       _ev->type = et; \
140       _ev->arg = (void *) _arg; \
141       if (/* skip backtrace for now */ \
142           false) \
143         { \
144           _ev->backtrace = \
145             backtrace_get ("", 40, false); \
146         } \
147       /* don't print events that are called \
148        * continuously */ \
149       if (et != ET_PLAYHEAD_POS_CHANGED) \
150         { \
151           g_debug ( \
152             "processing UI event now " #et \
153             " (%s:%d)", __func__, __LINE__); \
154         } \
155       event_manager_process_event ( \
156         EVENT_MANAGER, _ev); \
157       object_pool_return ( \
158         EVENT_MANAGER->obj_pool, _ev); \
159     }
160 
161 /**
162  * Creates the event queue and starts the event loop.
163  *
164  * Must be called from a GTK thread.
165  */
166 EventManager *
167 event_manager_new (void);
168 
169 /**
170  * Starts accepting events.
171  */
172 void
173 event_manager_start_events (
174   EventManager * self);
175 
176 /**
177  * Stops events from getting fired.
178  */
179 void
180 event_manager_stop_events (
181   EventManager * self);
182 
183 /**
184  * Processes the given event.
185  *
186  * The caller is responsible for putting the event
187  * back in the object pool if needed.
188  */
189 void
190 event_manager_process_event (
191   EventManager * self,
192   ZEvent *       ev);
193 
194 /**
195  * Processes the events now.
196  *
197  * Must only be called from the GTK thread.
198  */
199 void
200 event_manager_process_now (
201   EventManager * self);
202 
203 /**
204  * Removes events where the arg matches the
205  * given object.
206  */
207 void
208 event_manager_remove_events_for_obj (
209   EventManager * self,
210   void *         obj);
211 
212 void
213 event_manager_free (
214   EventManager * self);
215 
216 /**
217  * @}
218  */
219 
220 #endif
221