1 /*
2  * Clutter.
3  *
4  * An OpenGL based 'interactive canvas' library.
5  *
6  * Copyright (C) 2014 Canonical Ltd.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
20  *
21  * Authors:
22  *  Marco Trevisan <marco.trevisan@canonical.com>
23  */
24 
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28 
29 #include "clutter-debug.h"
30 #include "clutter-main.h"
31 #include "clutter-stage-private.h"
32 
33 #include "mir/clutter-backend-mir-priv.h"
34 #include "mir/clutter-backend-mir.h"
35 #include "mir/clutter-device-manager-mir.h"
36 #include "mir/clutter-event-mir.h"
37 #include "mir/clutter-stage-mir.h"
38 #include "mir/clutter-mir.h"
39 
40 G_DEFINE_TYPE (ClutterBackendMir, clutter_backend_mir, CLUTTER_TYPE_BACKEND);
41 
42 static MirConnection *_foreign_connection = NULL;
43 static gboolean _no_event_dispatch = FALSE;
44 
45 static gboolean
clutter_backend_mir_post_parse(ClutterBackend * backend,GError ** error)46 clutter_backend_mir_post_parse (ClutterBackend  *backend,
47                                 GError         **error)
48 {
49   ClutterBackendMir *backend_mir = CLUTTER_BACKEND_MIR (backend);
50 
51   backend_mir->mir_connection = _foreign_connection;
52   if (backend_mir->mir_connection == NULL)
53     backend_mir->mir_connection = mir_connect_sync (NULL, "Clutter");
54 
55   if (!mir_connection_is_valid (backend_mir->mir_connection))
56     {
57       g_set_error (error, CLUTTER_INIT_ERROR,
58                    CLUTTER_INIT_ERROR_BACKEND,
59                    "Failed to open Mir display socket %s",
60                    mir_connection_get_error_message (backend_mir->mir_connection));
61       mir_connection_release (backend_mir->mir_connection);
62       return FALSE;
63     }
64 
65   g_object_set (clutter_settings_get_default (), "font-dpi", 96 * 1024, NULL);
66 
67   return TRUE;
68 }
69 
70 static CoglRenderer *
clutter_backend_mir_get_renderer(ClutterBackend * backend,GError ** error)71 clutter_backend_mir_get_renderer (ClutterBackend  *backend,
72                                   GError         **error)
73 {
74   ClutterBackendMir *backend_mir = CLUTTER_BACKEND_MIR (backend);
75   CoglRenderer *renderer;
76 
77   CLUTTER_NOTE (BACKEND, "Creating a new Mir renderer");
78 
79   renderer = cogl_renderer_new ();
80 
81   cogl_renderer_set_winsys_id (renderer, COGL_WINSYS_ID_EGL_MIR);
82   cogl_mir_renderer_set_foreign_connection (renderer,
83                                             backend_mir->mir_connection);
84 
85   return renderer;
86 }
87 
88 static CoglDisplay *
clutter_backend_mir_get_display(ClutterBackend * backend,CoglRenderer * renderer,CoglSwapChain * swap_chain,GError ** error)89 clutter_backend_mir_get_display (ClutterBackend  *backend,
90                                  CoglRenderer    *renderer,
91                                  CoglSwapChain   *swap_chain,
92                                  GError         **error)
93 {
94   CoglOnscreenTemplate *onscreen_template = NULL;
95   CoglDisplay *display;
96 
97   onscreen_template = cogl_onscreen_template_new (swap_chain);
98 
99   if (!cogl_renderer_check_onscreen_template (renderer,
100                                               onscreen_template,
101                                               error))
102     goto error;
103 
104   display = cogl_display_new (renderer, onscreen_template);
105 
106   return display;
107 
108 error:
109   if (onscreen_template)
110     cogl_object_unref (onscreen_template);
111 
112   return NULL;
113 }
114 
115 static void
on_mir_event_cb(CoglMirEvent * mir_event,void * data)116 on_mir_event_cb (CoglMirEvent *mir_event,
117                  void *data)
118 {
119   ClutterBackend *backend = data;
120   _clutter_mir_handle_event (backend, mir_event->surface, mir_event->event);
121 }
122 
123 void
_clutter_events_mir_init(ClutterBackend * backend)124 _clutter_events_mir_init (ClutterBackend *backend)
125 {
126   ClutterBackendMir *backend_mir = CLUTTER_BACKEND_MIR (backend);
127   CoglRenderer *cogl_renderer = backend->cogl_renderer;
128 
129   backend->device_manager = _clutter_device_manager_mir_new (backend);
130 
131   if (_no_event_dispatch)
132     return;
133 
134   cogl_mir_renderer_add_event_listener (cogl_renderer, on_mir_event_cb, backend);
135   backend_mir->mir_source = _clutter_event_source_mir_new ();
136 }
137 
138 
139 static void
clutter_backend_mir_init(ClutterBackendMir * backend_mir)140 clutter_backend_mir_init (ClutterBackendMir *backend_mir)
141 {
142 }
143 
144 static void
clutter_backend_mir_dispose(GObject * gobject)145 clutter_backend_mir_dispose (GObject *gobject)
146 {
147   ClutterBackend *backend = CLUTTER_BACKEND (gobject);
148   ClutterBackendMir *backend_mir = CLUTTER_BACKEND_MIR (backend);
149   CoglRenderer *cogl_renderer = backend->cogl_renderer;
150 
151   g_clear_object (&backend->device_manager);
152   g_clear_pointer (&backend_mir->mir_source, g_source_unref);
153   cogl_mir_renderer_remove_event_listener (cogl_renderer, on_mir_event_cb,
154                                            backend);
155 
156   G_OBJECT_CLASS (clutter_backend_mir_parent_class)->dispose (gobject);
157 }
158 
159 static void
clutter_backend_mir_class_init(ClutterBackendMirClass * klass)160 clutter_backend_mir_class_init (ClutterBackendMirClass *klass)
161 {
162   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
163   ClutterBackendClass *backend_class = CLUTTER_BACKEND_CLASS (klass);
164 
165   gobject_class->dispose = clutter_backend_mir_dispose;
166 
167   backend_class->stage_window_type = CLUTTER_TYPE_STAGE_MIR;
168 
169   backend_class->post_parse = clutter_backend_mir_post_parse;
170   backend_class->get_renderer = clutter_backend_mir_get_renderer;
171   backend_class->get_display = clutter_backend_mir_get_display;
172 }
173 
174 ClutterBackend *
clutter_backend_mir_new(void)175 clutter_backend_mir_new (void)
176 {
177   return g_object_new (CLUTTER_TYPE_BACKEND_MIR, NULL);
178 }
179 
180 /**
181  * clutter_mir_set_connection:
182  * @connection: pointer to a mir connection
183  *
184  * Sets the display connection Clutter should use; must be called
185  * before clutter_init(), clutter_init_with_args() or other functions
186  * pertaining Clutter's initialization process.
187  *
188  * If you are parsing the command line arguments by retrieving Clutter's
189  * #GOptionGroup with clutter_get_option_group() and calling
190  * g_option_context_parse() yourself, you should also call
191  * clutter_mir_set_connection() before g_option_context_parse().
192  *
193  * Since: 1.22
194  */
195 void
clutter_mir_set_connection(MirConnection * connection)196 clutter_mir_set_connection (MirConnection *connection)
197 {
198   g_return_if_fail (mir_connection_is_valid (connection));
199 
200   if (_clutter_context_is_initialized ())
201     {
202       g_warning ("%s() can only be used before calling clutter_init()",
203                  G_STRFUNC);
204       return;
205     }
206 
207   _foreign_connection = connection;
208 }
209 
210 /**
211  * clutter_mir_disable_event_retrieval:
212  *
213  * Disables the dispatch of the events in the main loop.
214  *
215  * This is useful for integrating Clutter with another library that will do the
216  * event dispatch;
217  *
218  * This function can only be called before calling clutter_init().
219  *
220  * This function should not be normally used by applications.
221  *
222  * Since: 1.22
223  */
224 void
clutter_mir_disable_event_retrieval(void)225 clutter_mir_disable_event_retrieval (void)
226 {
227   if (_clutter_context_is_initialized ())
228     {
229       g_warning ("%s() can only be used before calling clutter_init()",
230                  G_STRFUNC);
231       return;
232     }
233 
234   _no_event_dispatch = TRUE;
235 }
236