180 | | static void |
181 | | _stroke_progress_notification (cairo_t *cr, |
182 | | gdouble progress) |
183 | | { |
184 | | cairo_set_line_width (cr, ARC_LINE_WIDTH); |
185 | | cairo_arc (cr, |
186 | | ANIM_WINDOW_WIDTH / 2, |
187 | | ANIM_WINDOW_WIDTH / 2, |
188 | | ANIM_WINDOW_WIDTH / 2 - ARC_LINE_WIDTH / 2, |
189 | | - G_PI_2, (2 * G_PI * progress) - G_PI_2); |
190 | | cairo_stroke (cr); |
191 | | } |
192 | | |
193 | | static gboolean |
194 | | _sugar_long_press_anim_draw (GtkWidget *widget, |
195 | | cairo_t *cr, |
196 | | SugarLongPressController *controller) |
197 | | { |
198 | | SugarLongPressControllerPriv *priv = controller->_priv; |
199 | | GtkStyleContext *context; |
200 | | gdouble progress; |
201 | | gint64 diff_msec; |
202 | | GdkRGBA color; |
203 | | |
204 | | diff_msec = (g_get_monotonic_time () - priv->start_time) / 1000; |
205 | | progress = (gdouble) diff_msec / priv->delay; |
206 | | |
207 | | context = gtk_widget_get_style_context (widget); |
208 | | gtk_style_context_save (context); |
209 | | cairo_save (cr); |
210 | | |
211 | | gtk_style_context_add_class (context, "long-press-notification"); |
212 | | gtk_style_context_get_color (context, GTK_STATE_FLAG_NORMAL, &color); |
213 | | |
214 | | gdk_cairo_set_source_rgba (cr, &color); |
215 | | _stroke_progress_notification (cr, progress); |
216 | | |
217 | | gtk_style_context_restore (context); |
218 | | cairo_restore (cr); |
219 | | |
220 | | return TRUE; |
221 | | } |
222 | | |
223 | | static void |
224 | | _sugar_long_press_controller_update_shape (GtkWidget *widget, |
225 | | SugarLongPressController *controller) |
226 | | { |
227 | | cairo_surface_t *surface; |
228 | | cairo_region_t *region; |
229 | | cairo_t *cr; |
230 | | |
231 | | surface = cairo_image_surface_create (CAIRO_FORMAT_A1, |
232 | | ANIM_WINDOW_WIDTH, |
233 | | ANIM_WINDOW_WIDTH); |
234 | | cr = cairo_create (surface); |
235 | | _stroke_progress_notification (cr, 1.0); |
236 | | cairo_destroy (cr); |
237 | | |
238 | | region = gdk_cairo_region_create_from_surface (surface); |
239 | | cairo_surface_destroy (surface); |
240 | | |
241 | | gtk_widget_shape_combine_region (widget, region); |
242 | | cairo_region_destroy (region); |
243 | | } |
244 | | |
245 | | static gboolean |
246 | | _sugar_long_press_anim_timeout (gpointer user_data) |
247 | | { |
248 | | SugarLongPressController *controller = user_data; |
249 | | SugarLongPressControllerPriv *priv = controller->_priv; |
250 | | GtkWidget *widget; |
251 | | |
252 | | g_object_get (controller, "widget", &widget, NULL); |
253 | | |
254 | | if (!widget) |
255 | | { |
256 | | priv->anim_id = 0; |
257 | | return FALSE; |
258 | | } |
259 | | |
260 | | if (priv->anim_window && |
261 | | gtk_widget_get_screen (widget) != |
262 | | gtk_widget_get_screen (priv->anim_window)) |
263 | | { |
264 | | gtk_widget_destroy (priv->anim_window); |
265 | | priv->anim_window = NULL; |
266 | | } |
267 | | |
268 | | if (!priv->anim_window) |
269 | | { |
270 | | GdkScreen *screen; |
271 | | GdkVisual *rgba_visual; |
272 | | |
273 | | priv->anim_window = gtk_window_new (GTK_WINDOW_POPUP); |
274 | | gtk_widget_set_app_paintable (priv->anim_window, TRUE); |
275 | | gtk_widget_input_shape_combine_region (priv->anim_window, NULL); |
276 | | gtk_window_set_type_hint (GTK_WINDOW (priv->anim_window), |
277 | | GDK_WINDOW_TYPE_HINT_UTILITY); |
278 | | |
279 | | screen = gtk_widget_get_screen (widget); |
280 | | rgba_visual = gdk_screen_get_rgba_visual (screen); |
281 | | |
282 | | gtk_window_set_screen (GTK_WINDOW (priv->anim_window), screen); |
283 | | |
284 | | if (rgba_visual && gdk_screen_is_composited (screen)) |
285 | | { |
286 | | GdkRGBA bg = { 0, 0, 0, 0 }; |
287 | | |
288 | | gtk_widget_set_visual (priv->anim_window, rgba_visual); |
289 | | gtk_widget_override_background_color (priv->anim_window, 0, &bg); |
290 | | } |
291 | | else |
292 | | _sugar_long_press_controller_update_shape (priv->anim_window, |
293 | | controller); |
294 | | |
295 | | g_signal_connect (priv->anim_window, "draw", |
296 | | G_CALLBACK (_sugar_long_press_anim_draw), |
297 | | controller); |
298 | | } |
299 | | |
300 | | if (!gtk_widget_get_visible (priv->anim_window)) |
301 | | { |
302 | | gtk_window_move (GTK_WINDOW (priv->anim_window), |
303 | | priv->root_x - (ANIM_WINDOW_WIDTH / 2), |
304 | | priv->root_y - (ANIM_WINDOW_WIDTH / 2)); |
305 | | gtk_window_resize (GTK_WINDOW (priv->anim_window), |
306 | | ANIM_WINDOW_WIDTH, ANIM_WINDOW_WIDTH); |
307 | | gtk_widget_show (priv->anim_window); |
308 | | |
309 | | priv->anim_id = |
310 | | gdk_threads_add_timeout (20, _sugar_long_press_anim_timeout, |
311 | | controller); |
312 | | return FALSE; |
313 | | } |
314 | | else |
315 | | { |
316 | | gtk_widget_queue_draw (priv->anim_window); |
317 | | return TRUE; |
318 | | } |
319 | | } |
320 | | |