1 /*
2 * stage: Global stage of application
3 *
4 * Copyright 2012-2020 Stephan Haller <nomad@froevel.de>
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 2 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, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 * MA 02110-1301, USA.
20 *
21 *
22 */
23
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27
28 #include <libxfdashboard/stage.h>
29
30 #include <glib/gi18n-lib.h>
31 #include <clutter/clutter.h>
32 #include <gtk/gtk.h>
33 #include <gdk/gdk.h>
34 #include <math.h>
35
36 #include <libxfdashboard/application.h>
37 #include <libxfdashboard/viewpad.h>
38 #include <libxfdashboard/view-selector.h>
39 #include <libxfdashboard/text-box.h>
40 #include <libxfdashboard/quicklaunch.h>
41 #include <libxfdashboard/applications-view.h>
42 #include <libxfdashboard/windows-view.h>
43 #include <libxfdashboard/search-view.h>
44 #include <libxfdashboard/toggle-button.h>
45 #include <libxfdashboard/workspace-selector.h>
46 #include <libxfdashboard/collapse-box.h>
47 #include <libxfdashboard/tooltip-action.h>
48 #include <libxfdashboard/stylable.h>
49 #include <libxfdashboard/utils.h>
50 #include <libxfdashboard/focus-manager.h>
51 #include <libxfdashboard/enums.h>
52 #include <libxfdashboard/window-tracker.h>
53 #include <libxfdashboard/window-content.h>
54 #include <libxfdashboard/stage-interface.h>
55 #include <libxfdashboard/compat.h>
56 #include <libxfdashboard/debug.h>
57
58
59 /* Define this class in GObject system */
60 struct _XfdashboardStagePrivate
61 {
62 /* Properties related */
63 XfdashboardStageBackgroundImageType backgroundType;
64
65 ClutterColor *backgroundColor;
66
67 /* Actors */
68 ClutterActor *backgroundImageLayer;
69 ClutterActor *backgroundColorLayer;
70
71 gpointer primaryInterface;
72 gpointer quicklaunch;
73 gpointer searchbox;
74 gpointer workspaces;
75 gpointer viewpad;
76 gpointer viewSelector;
77 gpointer notification;
78 gpointer tooltip;
79
80 /* Instance related */
81 XfdashboardWindowTracker *windowTracker;
82 XfdashboardWindowTrackerWindow *stageWindow;
83
84 gboolean searchActive;
85 gint lastSearchTextLength;
86 XfdashboardView *viewBeforeSearch;
87 gchar *switchToView;
88 gpointer focusActorOnShow;
89
90 guint notificationTimeoutID;
91
92 XfdashboardFocusManager *focusManager;
93 };
94
95 G_DEFINE_TYPE_WITH_PRIVATE(XfdashboardStage,
96 xfdashboard_stage,
97 CLUTTER_TYPE_STAGE)
98
99 /* Properties */
100 enum
101 {
102 PROP_0,
103
104 PROP_BACKGROUND_IMAGE_TYPE,
105 PROP_BACKGROUND_COLOR,
106
107 PROP_SWITCH_TO_VIEW,
108
109 PROP_LAST
110 };
111
112 static GParamSpec* XfdashboardStageProperties[PROP_LAST]={ 0, };
113
114 /* Signals */
115 enum
116 {
117 SIGNAL_ACTOR_CREATED,
118
119 SIGNAL_SEARCH_STARTED,
120 SIGNAL_SEARCH_CHANGED,
121 SIGNAL_SEARCH_ENDED,
122
123 SIGNAL_SHOW_TOOLTIP,
124 SIGNAL_HIDE_TOOLTIP,
125
126 SIGNAL_LAST
127 };
128
129 static guint XfdashboardStageSignals[SIGNAL_LAST]={ 0, };
130
131
132 /* Forward declaration */
133 static void _xfdashboard_stage_on_window_opened(XfdashboardStage *self,
134 XfdashboardWindowTrackerWindow *inWindow,
135 gpointer inUserData);
136
137
138 /* IMPLEMENTATION: Private variables and methods */
139 #define NOTIFICATION_TIMEOUT_XFCONF_PROP "/min-notification-timeout"
140 #define DEFAULT_NOTIFICATION_TIMEOUT 3000
141 #define RESET_SEARCH_ON_RESUME_XFCONF_PROP "/reset-search-on-resume"
142 #define DEFAULT_RESET_SEARCH_ON_RESUME TRUE
143 #define SWITCH_VIEW_ON_RESUME_XFCONF_PROP "/switch-to-view-on-resume"
144 #define DEFAULT_SWITCH_VIEW_ON_RESUME NULL
145 #define RESELECT_THEME_FOCUS_ON_RESUME_XFCONF_PROP "/reselect-theme-focus-on-resume"
146 #define DEFAULT_RESELECT_THEME_FOCUS_ON_RESUME FALSE
147 #define XFDASHBOARD_THEME_LAYOUT_PRIMARY "primary"
148 #define XFDASHBOARD_THEME_LAYOUT_SECONDARY "secondary"
149
150 typedef struct _XfdashboardStageThemeInterfaceData XfdashboardStageThemeInterfaceData;
151 struct _XfdashboardStageThemeInterfaceData
152 {
153 ClutterActor *actor;
154 GPtrArray *focusables;
155 ClutterActor *focus;
156 };
157
158 /* Handle an event */
_xfdashboard_stage_event(ClutterActor * inActor,ClutterEvent * inEvent)159 static gboolean _xfdashboard_stage_event(ClutterActor *inActor, ClutterEvent *inEvent)
160 {
161 XfdashboardStage *self;
162 XfdashboardStagePrivate *priv;
163 gboolean result;
164
165 g_return_val_if_fail(XFDASHBOARD_IS_STAGE(inActor), CLUTTER_EVENT_PROPAGATE);
166
167 self=XFDASHBOARD_STAGE(inActor);
168 priv=self->priv;
169
170 /* Do only intercept any event if a focus manager is available */
171 if(!priv->focusManager) return(CLUTTER_EVENT_PROPAGATE);
172
173 /* Do only intercept "key-press" and "key-release" events */
174 if(clutter_event_type(inEvent)!=CLUTTER_KEY_PRESS &&
175 clutter_event_type(inEvent)!=CLUTTER_KEY_RELEASE)
176 {
177 return(CLUTTER_EVENT_PROPAGATE);
178 }
179
180 /* Handle key release event */
181 if(clutter_event_type(inEvent)==CLUTTER_KEY_RELEASE)
182 {
183 /* Handle key */
184 switch(inEvent->key.keyval)
185 {
186 /* Handle ESC key to clear search box or quit/suspend application */
187 case CLUTTER_KEY_Escape:
188 {
189 /* If search is active then end search by clearing search box ... */
190 if(priv->searchbox &&
191 !xfdashboard_text_box_is_empty(XFDASHBOARD_TEXT_BOX(priv->searchbox)))
192 {
193 xfdashboard_text_box_set_text(XFDASHBOARD_TEXT_BOX(priv->searchbox), NULL);
194 return(CLUTTER_EVENT_STOP);
195 }
196 /* ... otherwise quit application */
197 else
198 {
199 xfdashboard_application_suspend_or_quit(NULL);
200 return(CLUTTER_EVENT_STOP);
201 }
202 }
203 break;
204
205 default:
206 /* Fallthrough */
207 break;
208 }
209 }
210
211 /* Ask focus manager to handle this event */
212 result=xfdashboard_focus_manager_handle_key_event(priv->focusManager, inEvent, NULL);
213 if(result==CLUTTER_EVENT_STOP) return(result);
214
215 /* If even focus manager did not handle this event send this event to searchbox */
216 if(priv->searchbox &&
217 XFDASHBOARD_IS_FOCUSABLE(priv->searchbox) &&
218 xfdashboard_focus_manager_is_registered(priv->focusManager, XFDASHBOARD_FOCUSABLE(priv->searchbox)))
219 {
220 /* Ask search to handle this event if it has not the focus currently
221 * because in this case it has already handled the event and we do
222 * not to do this twice.
223 */
224 if(xfdashboard_focus_manager_get_focus(priv->focusManager)!=XFDASHBOARD_FOCUSABLE(priv->searchbox))
225 {
226 result=xfdashboard_focus_manager_handle_key_event(priv->focusManager, inEvent, XFDASHBOARD_FOCUSABLE(priv->searchbox));
227 if(result==CLUTTER_EVENT_STOP) return(result);
228 }
229 }
230
231 /* If we get here there was no searchbox or it could not handle the event
232 * so stop further processing.
233 */
234 return(CLUTTER_EVENT_STOP);
235 }
236
237 /* Get view to switch to by first looking upr temporary view ID set via command-line
238 * and if not found or not set then looking up view ID configured via settings.
239 */
_xfdashboard_stage_get_view_to_switch_to(XfdashboardStage * self)240 static XfdashboardView* _xfdashboard_stage_get_view_to_switch_to(XfdashboardStage *self)
241 {
242 XfdashboardStagePrivate *priv;
243 XfdashboardView *view;
244
245 g_return_val_if_fail(XFDASHBOARD_IS_STAGE(self), NULL);
246
247 priv=self->priv;
248 view=NULL;
249
250 /* First lookup view at private variable 'switchToView' which has higher
251 * priority as it is a temporary value and is usually set via command-line.
252 */
253 if(priv->switchToView)
254 {
255 view=xfdashboard_viewpad_find_view_by_id(XFDASHBOARD_VIEWPAD(priv->viewpad), priv->switchToView);
256 if(!view) g_warning("Will not switch to unknown view '%s'", priv->switchToView);
257
258 /* Regardless if we could find view by its internal name or not
259 * reset variable because the switch should happen once only.
260 */
261 g_free(priv->switchToView);
262 priv->switchToView=NULL;
263
264 /* Notify about property change */
265 g_object_notify_by_pspec(G_OBJECT(self), XfdashboardStageProperties[PROP_SWITCH_TO_VIEW]);
266 }
267
268 /* If we have not to switch to a specific view or if this view cannot be found
269 * then lookup the configured view in settings by its internal name
270 */
271 if(!view)
272 {
273 gchar *resumeViewID;
274
275 /* Get view ID from settings and look up view */
276 resumeViewID=xfconf_channel_get_string(xfdashboard_application_get_xfconf_channel(NULL),
277 SWITCH_VIEW_ON_RESUME_XFCONF_PROP,
278 DEFAULT_SWITCH_VIEW_ON_RESUME);
279 if(resumeViewID)
280 {
281 /* Lookup view by its ID set configured settings */
282 view=xfdashboard_viewpad_find_view_by_id(XFDASHBOARD_VIEWPAD(priv->viewpad), resumeViewID);
283 if(!view) g_warning("Cannot switch to unknown view '%s'", resumeViewID);
284
285 /* Release allocated resources */
286 g_free(resumeViewID);
287 }
288 }
289
290 /* Return view found */
291 return(view);
292 }
293
294 /* Set focus in stage */
_xfdashboard_stage_set_focus(XfdashboardStage * self)295 static void _xfdashboard_stage_set_focus(XfdashboardStage *self)
296 {
297 XfdashboardStagePrivate *priv;
298 XfdashboardFocusable *actor;
299
300 g_return_if_fail(XFDASHBOARD_IS_STAGE(self));
301
302 priv=self->priv;
303
304 /* Set focus if no focus is set */
305 actor=xfdashboard_focus_manager_get_focus(priv->focusManager);
306 if(!actor)
307 {
308 XfdashboardFocusable *focusable;
309
310 /* First try to set focus to searchbox ... */
311 if(XFDASHBOARD_IS_FOCUSABLE(priv->searchbox) &&
312 xfdashboard_focusable_can_focus(XFDASHBOARD_FOCUSABLE(priv->searchbox)))
313 {
314 xfdashboard_focus_manager_set_focus(priv->focusManager, XFDASHBOARD_FOCUSABLE(priv->searchbox));
315 }
316 /* ... then lookup first focusable actor */
317 else
318 {
319 focusable=xfdashboard_focus_manager_get_next_focusable(priv->focusManager, NULL);
320 if(focusable) xfdashboard_focus_manager_set_focus(priv->focusManager, focusable);
321 }
322 }
323 }
324
325 /* Stage got signal to show a tooltip */
_xfdashboard_stage_show_tooltip(XfdashboardStage * self,ClutterAction * inAction)326 static void _xfdashboard_stage_show_tooltip(XfdashboardStage *self, ClutterAction *inAction)
327 {
328 XfdashboardStagePrivate *priv;
329 XfdashboardTooltipAction *tooltipAction;
330 const gchar *tooltipText;
331 gfloat tooltipX, tooltipY;
332 gfloat tooltipWidth, tooltipHeight;
333 guint cursorSize;
334 gfloat x, y;
335 gfloat stageWidth, stageHeight;
336
337 g_return_if_fail(XFDASHBOARD_IS_STAGE(self));
338 g_return_if_fail(XFDASHBOARD_IS_TOOLTIP_ACTION(inAction));
339 g_return_if_fail(self->priv->tooltip);
340
341 priv=self->priv;
342 tooltipAction=XFDASHBOARD_TOOLTIP_ACTION(inAction);
343
344 /* Hide tooltip while setup to avoid flicker */
345 clutter_actor_hide(priv->tooltip);
346
347 /* Get tooltip text and update text in tooltip actor */
348 tooltipText=xfdashboard_tooltip_action_get_text(tooltipAction);
349 xfdashboard_text_box_set_text(XFDASHBOARD_TEXT_BOX(priv->tooltip), tooltipText);
350
351 /* Determine coordinates where to show tooltip at */
352 xfdashboard_tooltip_action_get_position(tooltipAction, &tooltipX, &tooltipY);
353 clutter_actor_get_size(priv->tooltip, &tooltipWidth, &tooltipHeight);
354
355 cursorSize=gdk_display_get_default_cursor_size(gdk_display_get_default());
356
357 clutter_actor_get_size(CLUTTER_ACTOR(self), &stageWidth, &stageHeight);
358
359 x=tooltipX+cursorSize;
360 y=tooltipY+cursorSize;
361 if((x+tooltipWidth)>stageWidth) x=tooltipX-tooltipWidth;
362 if((y+tooltipHeight)>stageHeight) y=tooltipY-tooltipHeight;
363
364 clutter_actor_set_position(priv->tooltip, floor(x), floor(y));
365
366 /* Show tooltip */
367 clutter_actor_show(priv->tooltip);
368 }
369
370 /* Stage got signal to hide tooltip */
_xfdashboard_stage_hide_tooltip(XfdashboardStage * self,ClutterAction * inAction)371 static void _xfdashboard_stage_hide_tooltip(XfdashboardStage *self, ClutterAction *inAction)
372 {
373 XfdashboardStagePrivate *priv;
374
375 g_return_if_fail(XFDASHBOARD_IS_STAGE(self));
376
377 priv=self->priv;
378
379 /* Hide tooltip */
380 clutter_actor_hide(priv->tooltip);
381 }
382
383 /* Notification timeout has been reached */
_xfdashboard_stage_on_notification_timeout_destroyed(gpointer inUserData)384 static void _xfdashboard_stage_on_notification_timeout_destroyed(gpointer inUserData)
385 {
386 XfdashboardStage *self;
387 XfdashboardStagePrivate *priv;
388
389 g_return_if_fail(XFDASHBOARD_IS_STAGE(inUserData));
390
391 self=XFDASHBOARD_STAGE(inUserData);
392 priv=self->priv;
393
394 /* Timeout source was destroy so just reset ID to 0 */
395 priv->notificationTimeoutID=0;
396 }
397
_xfdashboard_stage_on_notification_timeout(gpointer inUserData)398 static gboolean _xfdashboard_stage_on_notification_timeout(gpointer inUserData)
399 {
400 XfdashboardStage *self;
401 XfdashboardStagePrivate *priv;
402
403 g_return_val_if_fail(XFDASHBOARD_IS_STAGE(inUserData), G_SOURCE_REMOVE);
404
405 self=XFDASHBOARD_STAGE(inUserData);
406 priv=self->priv;
407
408 /* Timeout reached so hide notification */
409 clutter_actor_hide(priv->notification);
410
411 /* Tell main context to remove this source */
412 return(G_SOURCE_REMOVE);
413 }
414
415 /* App-button was toggled */
_xfdashboard_stage_on_quicklaunch_apps_button_toggled(XfdashboardStage * self,gpointer inUserData)416 static void _xfdashboard_stage_on_quicklaunch_apps_button_toggled(XfdashboardStage *self, gpointer inUserData)
417 {
418 XfdashboardStagePrivate *priv;
419 XfdashboardToggleButton *appsButton;
420 gboolean state;
421 XfdashboardView *view;
422
423 g_return_if_fail(XFDASHBOARD_IS_STAGE(self));
424 g_return_if_fail(XFDASHBOARD_IS_TOGGLE_BUTTON(inUserData));
425
426 priv=self->priv;
427 appsButton=XFDASHBOARD_TOGGLE_BUTTON(inUserData);
428
429 /* Get state of apps button */
430 state=xfdashboard_toggle_button_get_toggle_state(appsButton);
431
432 /* Depending on state activate views */
433 if(state==FALSE)
434 {
435 /* Find "windows-view" view and activate */
436 view=xfdashboard_viewpad_find_view_by_type(XFDASHBOARD_VIEWPAD(priv->viewpad), XFDASHBOARD_TYPE_WINDOWS_VIEW);
437 if(view) xfdashboard_viewpad_set_active_view(XFDASHBOARD_VIEWPAD(priv->viewpad), view);
438 }
439 else
440 {
441 /* Find "applications" or "search" view and activate */
442 if(!priv->searchActive) view=xfdashboard_viewpad_find_view_by_type(XFDASHBOARD_VIEWPAD(priv->viewpad), XFDASHBOARD_TYPE_APPLICATIONS_VIEW);
443 else view=xfdashboard_viewpad_find_view_by_type(XFDASHBOARD_VIEWPAD(priv->viewpad), XFDASHBOARD_TYPE_SEARCH_VIEW);
444 if(view) xfdashboard_viewpad_set_active_view(XFDASHBOARD_VIEWPAD(priv->viewpad), view);
445 }
446 }
447
448 /* Text in search text-box has changed */
_xfdashboard_stage_on_searchbox_text_changed(XfdashboardStage * self,gchar * inText,gpointer inUserData)449 static void _xfdashboard_stage_on_searchbox_text_changed(XfdashboardStage *self,
450 gchar *inText,
451 gpointer inUserData)
452 {
453 XfdashboardStagePrivate *priv;
454 XfdashboardTextBox *textBox=XFDASHBOARD_TEXT_BOX(inUserData);
455 XfdashboardView *searchView;
456 gint textLength;
457 const gchar *text;
458 XfdashboardToggleButton *appsButton;
459
460 g_return_if_fail(XFDASHBOARD_IS_STAGE(self));
461 g_return_if_fail(XFDASHBOARD_IS_TEXT_BOX(inUserData));
462
463 priv=self->priv;
464
465 /* Get search view */
466 searchView=xfdashboard_viewpad_find_view_by_type(XFDASHBOARD_VIEWPAD(priv->viewpad), XFDASHBOARD_TYPE_SEARCH_VIEW);
467 if(searchView==NULL)
468 {
469 g_critical("Cannot perform search because search view was not found in viewpad.");
470 return;
471 }
472
473 /* Get text and length of text in text-box */
474 text=xfdashboard_text_box_get_text(textBox);
475 textLength=xfdashboard_text_box_get_length(textBox);
476
477 /* Get apps button of quicklaunch */
478 appsButton=xfdashboard_quicklaunch_get_apps_button(XFDASHBOARD_QUICKLAUNCH(priv->quicklaunch));
479
480 /* Check if current text length if greater than zero and previous text length
481 * was zero. If check is successful it marks the start of a search. Emit the
482 * "search-started" signal. There is no need to start a search a search over
483 * all search providers as it will be done later by updating search criteria.
484 * There is also no need to activate search view because we will ensure that
485 * search view is activate on any change in search text box but we enable that
486 * view to be able to activate it ;)
487 */
488 if(textLength>0 && priv->lastSearchTextLength==0)
489 {
490 /* Remember current active view to restore it when search ended */
491 priv->viewBeforeSearch=XFDASHBOARD_VIEW(g_object_ref(xfdashboard_viewpad_get_active_view(XFDASHBOARD_VIEWPAD(priv->viewpad))));
492
493 /* Enable search view and set focus to viewpad which will show the
494 * search view so this search view will get the focus finally
495 */
496 xfdashboard_view_set_enabled(searchView, TRUE);
497 if(priv->viewpad && priv->focusManager)
498 {
499 xfdashboard_focus_manager_set_focus(priv->focusManager, XFDASHBOARD_FOCUSABLE(priv->viewpad));
500 }
501
502 /* Activate "clear" button on text box */
503 xfdashboard_stylable_add_class(XFDASHBOARD_STYLABLE(priv->searchbox), "search-active");
504
505 /* Change apps button appearance */
506 if(appsButton) xfdashboard_stylable_add_class(XFDASHBOARD_STYLABLE(appsButton), "search-active");
507
508 /* Emit "search-started" signal */
509 g_signal_emit(self, XfdashboardStageSignals[SIGNAL_SEARCH_STARTED], 0);
510 priv->searchActive=TRUE;
511 }
512
513 /* Ensure that search view is active, emit signal for text changed,
514 * update search criteria and set active toggle state at apps button
515 */
516 xfdashboard_viewpad_set_active_view(XFDASHBOARD_VIEWPAD(priv->viewpad), searchView);
517 xfdashboard_search_view_update_search(XFDASHBOARD_SEARCH_VIEW(searchView), text);
518 g_signal_emit(self, XfdashboardStageSignals[SIGNAL_SEARCH_CHANGED], 0, text);
519
520 if(appsButton) xfdashboard_toggle_button_set_toggle_state(appsButton, TRUE);
521
522 /* Check if current text length is zero and previous text length was greater
523 * than zero. If check is successful it marks the end of current search. Emit
524 * the "search-ended" signal, reactivate view before search was started and
525 * disable search view.
526 */
527 if(textLength==0 && priv->lastSearchTextLength>0)
528 {
529 /* Reactivate active view before search has started */
530 if(priv->viewBeforeSearch)
531 {
532 xfdashboard_viewpad_set_active_view(XFDASHBOARD_VIEWPAD(priv->viewpad), priv->viewBeforeSearch);
533 g_object_unref(priv->viewBeforeSearch);
534 priv->viewBeforeSearch=NULL;
535 }
536
537 /* Deactivate "clear" button on text box */
538 xfdashboard_stylable_remove_class(XFDASHBOARD_STYLABLE(priv->searchbox), "search-active");
539
540 /* Disable search view */
541 xfdashboard_view_set_enabled(searchView, FALSE);
542
543 /* Change apps button appearance */
544 if(appsButton) xfdashboard_stylable_remove_class(XFDASHBOARD_STYLABLE(appsButton), "search-active");
545
546 /* Emit "search-ended" signal */
547 g_signal_emit(self, XfdashboardStageSignals[SIGNAL_SEARCH_ENDED], 0);
548 priv->searchActive=FALSE;
549 }
550
551 /* Trace text length changes */
552 priv->lastSearchTextLength=textLength;
553 }
554
555 /* Secondary icon ("clear") on text box was clicked */
_xfdashboard_stage_on_searchbox_secondary_icon_clicked(XfdashboardStage * self,gpointer inUserData)556 static void _xfdashboard_stage_on_searchbox_secondary_icon_clicked(XfdashboardStage *self, gpointer inUserData)
557 {
558 XfdashboardTextBox *textBox;
559
560 g_return_if_fail(XFDASHBOARD_IS_STAGE(self));
561 g_return_if_fail(XFDASHBOARD_IS_TEXT_BOX(inUserData));
562
563 textBox=XFDASHBOARD_TEXT_BOX(inUserData);
564
565 /* Clear search text box */
566 xfdashboard_text_box_set_text(textBox, NULL);
567 }
568
569 /* Active view in viewpad has changed */
_xfdashboard_stage_on_view_activated(XfdashboardStage * self,XfdashboardView * inView,gpointer inUserData)570 static void _xfdashboard_stage_on_view_activated(XfdashboardStage *self, XfdashboardView *inView, gpointer inUserData)
571 {
572 XfdashboardStagePrivate *priv;
573 XfdashboardViewpad *viewpad G_GNUC_UNUSED;
574 XfdashboardToggleButton *appsButton;
575
576 g_return_if_fail(XFDASHBOARD_IS_STAGE(self));
577 g_return_if_fail(XFDASHBOARD_IS_VIEWPAD(inUserData));
578
579 priv=self->priv;
580 viewpad=XFDASHBOARD_VIEWPAD(inUserData);
581
582 /* If we have remembered a view "before-search" then a search is going on.
583 * If user switches between views while a search is going on remember the
584 * last one activated to restore it when search ends but do not remember
585 * the search view!
586 */
587 if(priv->viewBeforeSearch &&
588 G_OBJECT_TYPE(inView)!=XFDASHBOARD_TYPE_SEARCH_VIEW)
589 {
590 /* Release old remembered view */
591 g_object_unref(priv->viewBeforeSearch);
592
593 /* Remember new active view */
594 priv->viewBeforeSearch=XFDASHBOARD_VIEW(g_object_ref(inView));
595 }
596
597 /* Toggle application button in quicklaunch */
598 appsButton=xfdashboard_quicklaunch_get_apps_button(XFDASHBOARD_QUICKLAUNCH(priv->quicklaunch));
599 if(appsButton)
600 {
601 /* Block our signal handler at stage which is called when apps button's
602 * state changes because it will enforce a specific view depending on its
603 * state which may not be the view which is going to be activated.
604 */
605 g_signal_handlers_block_by_func(appsButton, _xfdashboard_stage_on_quicklaunch_apps_button_toggled, self);
606
607 /* Update toggle state of apps button */
608 if(G_OBJECT_TYPE(inView)==XFDASHBOARD_TYPE_SEARCH_VIEW ||
609 G_OBJECT_TYPE(inView)==XFDASHBOARD_TYPE_APPLICATIONS_VIEW)
610 {
611 xfdashboard_toggle_button_set_toggle_state(appsButton, TRUE);
612 }
613 else
614 {
615 xfdashboard_toggle_button_set_toggle_state(appsButton, FALSE);
616 }
617
618 /* Unblock any handler we blocked before */
619 g_signal_handlers_unblock_by_func(appsButton, _xfdashboard_stage_on_quicklaunch_apps_button_toggled, self);
620 }
621 }
622
623 /* A window was closed
624 * Check if stage window was closed then unset up window properties and reinstall
625 * signal handler to find new stage window.
626 */
_xfdashboard_stage_on_window_closed(XfdashboardStage * self,gpointer inUserData)627 static void _xfdashboard_stage_on_window_closed(XfdashboardStage *self,
628 gpointer inUserData)
629 {
630 XfdashboardStagePrivate *priv;
631 XfdashboardWindowTrackerWindow *window;
632
633 g_return_if_fail(XFDASHBOARD_IS_STAGE(self));
634 g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW(inUserData));
635
636 priv=self->priv;
637 window=XFDASHBOARD_WINDOW_TRACKER_WINDOW(inUserData);
638
639 /* Check if window closed is this stage window */
640 if(priv->stageWindow!=window) return;
641
642 /* Disconnect this signal handler as this stage window was closed*/
643 XFDASHBOARD_DEBUG(self, ACTOR, "Stage window was closed. Removing signal handler");
644 g_signal_handlers_disconnect_by_func(priv->stageWindow, G_CALLBACK(_xfdashboard_stage_on_window_closed), self);
645
646 /* Forget stage window as it was closed */
647 priv->stageWindow=NULL;
648
649 /* Instead reconnect signal handler to find new stage window */
650 XFDASHBOARD_DEBUG(self, ACTOR, "Reconnecting signal to find new stage window as this one as closed");
651 g_signal_connect_swapped(priv->windowTracker, "window-opened", G_CALLBACK(_xfdashboard_stage_on_window_opened), self);
652
653 /* Set focus */
654 _xfdashboard_stage_set_focus(self);
655 }
656
657
658 /* A window was created
659 * Check for stage window and set up window properties
660 */
_xfdashboard_stage_on_window_opened(XfdashboardStage * self,XfdashboardWindowTrackerWindow * inWindow,gpointer inUserData)661 static void _xfdashboard_stage_on_window_opened(XfdashboardStage *self,
662 XfdashboardWindowTrackerWindow *inWindow,
663 gpointer inUserData)
664 {
665 XfdashboardStagePrivate *priv;
666 XfdashboardWindowTrackerWindow *stageWindow;
667
668 g_return_if_fail(XFDASHBOARD_IS_STAGE(self));
669 g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW(inWindow));
670
671 priv=self->priv;
672
673 /* Check if window opened is this stage window */
674 stageWindow=xfdashboard_window_tracker_get_stage_window(priv->windowTracker, CLUTTER_STAGE(self));
675 if(stageWindow!=inWindow) return;
676
677 /* Set up window for use as stage window */
678 priv->stageWindow=inWindow;
679 xfdashboard_window_tracker_window_show_stage(priv->stageWindow);
680
681 /* Disconnect this signal handler as this is a one-time setup of stage window */
682 XFDASHBOARD_DEBUG(self, ACTOR, "Stage window was opened and set up. Removing signal handler");
683 g_signal_handlers_disconnect_by_func(priv->windowTracker, G_CALLBACK(_xfdashboard_stage_on_window_opened), self);
684
685 /* Instead connect signal handler to get notified when this stage window was
686 * destroyed as we need to forget this window and to reinstall this signal
687 * handler again.
688 */
689 XFDASHBOARD_DEBUG(self, ACTOR, "Connecting signal signal handler to get notified about destruction of stage window");
690 g_signal_connect_swapped(priv->stageWindow,
691 "closed",
692 G_CALLBACK(_xfdashboard_stage_on_window_closed),
693 self);
694
695 /* Set focus */
696 _xfdashboard_stage_set_focus(self);
697 }
698
699 /* A window was created
700 * Check if window opened is desktop background window
701 */
_xfdashboard_stage_on_desktop_window_opened(XfdashboardStage * self,XfdashboardWindowTrackerWindow * inWindow,gpointer inUserData)702 static void _xfdashboard_stage_on_desktop_window_opened(XfdashboardStage *self,
703 XfdashboardWindowTrackerWindow *inWindow,
704 gpointer inUserData)
705 {
706 XfdashboardStagePrivate *priv;
707 XfdashboardWindowTrackerWindow *desktopWindow;
708 ClutterContent *windowContent;
709
710 g_return_if_fail(XFDASHBOARD_IS_STAGE(self));
711 g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW(inWindow));
712
713 priv=self->priv;
714
715 /* Get desktop background window and check if it is the new window opened */
716 desktopWindow=xfdashboard_window_tracker_get_root_window(priv->windowTracker);
717 if(desktopWindow)
718 {
719 windowContent=xfdashboard_window_tracker_window_get_content(desktopWindow);
720 clutter_actor_set_content(priv->backgroundImageLayer, windowContent);
721 clutter_actor_show(priv->backgroundImageLayer);
722 g_object_unref(windowContent);
723
724 g_signal_handlers_disconnect_by_func(priv->windowTracker, G_CALLBACK(_xfdashboard_stage_on_desktop_window_opened), self);
725 XFDASHBOARD_DEBUG(self, ACTOR, "Found desktop window with signal 'window-opened', so disconnecting signal handler");
726 }
727 }
728
729 /* The application will be suspended */
_xfdashboard_stage_on_application_suspend(XfdashboardStage * self,gpointer inUserData)730 static void _xfdashboard_stage_on_application_suspend(XfdashboardStage *self, gpointer inUserData)
731 {
732 XfdashboardStagePrivate *priv;
733
734 g_return_if_fail(XFDASHBOARD_IS_STAGE(self));
735 g_return_if_fail(XFDASHBOARD_IS_APPLICATION(inUserData));
736
737 priv=self->priv;
738
739 /* Instead of hiding stage actor just hide stage's window. It should be safe
740 * to just hide the window as it should be listed on any task list and is not
741 * selectable by user. The advantage should be that the window is already mapped
742 * and its state is already set up like fullscreen, sticky and so on. This
743 * prevents that window will not be shown in fullscreen again (just maximized
744 * and flickers) if we use clutter_actor_show to show stage actor and its window
745 * again. But we can only do this if the window is known and set up ;)
746 */
747 if(priv->stageWindow)
748 {
749 xfdashboard_window_tracker_window_hide_stage(priv->stageWindow);
750 }
751
752 /* Hide tooltip */
753 if(priv->tooltip) clutter_actor_hide(priv->tooltip);
754 }
755
756 /* The application will be resumed */
_xfdashboard_stage_on_application_resume(XfdashboardStage * self,gpointer inUserData)757 static void _xfdashboard_stage_on_application_resume(XfdashboardStage *self, gpointer inUserData)
758 {
759 XfdashboardStagePrivate *priv;
760
761 g_return_if_fail(XFDASHBOARD_IS_STAGE(self));
762 g_return_if_fail(XFDASHBOARD_IS_APPLICATION(inUserData));
763
764 priv=self->priv;
765
766 /* If stage window is known just show it again ... */
767 if(priv->stageWindow)
768 {
769 gboolean doResetSearch;
770 XfdashboardView *searchView;
771 XfdashboardView *resumeView;
772
773 /* Get configured options */
774 doResetSearch=xfconf_channel_get_bool(xfdashboard_application_get_xfconf_channel(NULL),
775 RESET_SEARCH_ON_RESUME_XFCONF_PROP,
776 DEFAULT_RESET_SEARCH_ON_RESUME);
777
778 /* Find search view */
779 searchView=xfdashboard_viewpad_find_view_by_type(XFDASHBOARD_VIEWPAD(priv->viewpad), XFDASHBOARD_TYPE_SEARCH_VIEW);
780 if(!searchView) g_critical("Cannot find search view in viewpad to reset view.");
781
782 /* Find view to switch to if requested */
783 resumeView=_xfdashboard_stage_get_view_to_switch_to(self);
784
785 /* If view to switch to is the search view behave like we did not find the view
786 * because it does not make sense to switch to a view which might be hidden,
787 * e.g. when resetting search on resume which causes the search view to be hidden
788 * and the previous view to be shown.
789 */
790 if(resumeView &&
791 searchView &&
792 resumeView==searchView)
793 {
794 resumeView=NULL;
795 }
796
797 /* If search is active then end search by clearing search box if requested ... */
798 if(priv->searchbox &&
799 doResetSearch &&
800 !xfdashboard_text_box_is_empty(XFDASHBOARD_TEXT_BOX(priv->searchbox)))
801 {
802 /* If user wants to switch to a specific view set it as "previous" view now.
803 * It will be restored automatically when search box is cleared.
804 */
805 if(resumeView)
806 {
807 /* Release old remembered view */
808 if(priv->viewBeforeSearch) g_object_unref(priv->viewBeforeSearch);
809
810 /* Remember new active view */
811 priv->viewBeforeSearch=XFDASHBOARD_VIEW(g_object_ref(resumeView));
812 }
813
814 /* Reset search in search view */
815 if(searchView) xfdashboard_search_view_reset_search(XFDASHBOARD_SEARCH_VIEW(searchView));
816
817 /* Reset text in search box */
818 xfdashboard_text_box_set_text(XFDASHBOARD_TEXT_BOX(priv->searchbox), NULL);
819 }
820 /* ... otherwise just switch to view if requested */
821 else if(resumeView)
822 {
823 xfdashboard_viewpad_set_active_view(XFDASHBOARD_VIEWPAD(priv->viewpad), resumeView);
824 }
825
826 /* Now move focus to actor if user requested to refocus preselected actor
827 * as specified by theme.
828 */
829 if(priv->focusActorOnShow)
830 {
831 gboolean reselectFocusOnResume;
832
833 /* Determine if user (also) requests to reselect focus on resume */
834 reselectFocusOnResume=xfconf_channel_get_bool(xfdashboard_application_get_xfconf_channel(NULL),
835 RESELECT_THEME_FOCUS_ON_RESUME_XFCONF_PROP,
836 DEFAULT_RESELECT_THEME_FOCUS_ON_RESUME);
837 if(reselectFocusOnResume)
838 {
839 /* Move focus to actor */
840 xfdashboard_focus_manager_set_focus(priv->focusManager, XFDASHBOARD_FOCUSABLE(priv->focusActorOnShow));
841
842 XFDASHBOARD_DEBUG(self, ACTOR,
843 "Moved focus to actor %s because it should be reselected on resume",
844 G_OBJECT_TYPE_NAME(priv->focusActorOnShow));
845 }
846 else
847 {
848 /* Forget actor to focus now the user did not requested to reselect
849 * this focus again and again when stage window is shown ;)
850 */
851 g_object_remove_weak_pointer(G_OBJECT(priv->focusActorOnShow), &priv->focusActorOnShow);
852 priv->focusActorOnShow=NULL;
853 }
854 }
855
856 /* Set up stage and show it */
857 xfdashboard_window_tracker_window_show_stage(priv->stageWindow);
858 }
859 /* ... otherwise set it up by calling clutter_actor_show() etc. */
860 else
861 {
862 /* Show stage and force window creation. It will also handle
863 * the switch to a specific view.
864 */
865 clutter_actor_show(CLUTTER_ACTOR(self));
866 }
867
868 /* In any case force a redraw */
869 clutter_actor_queue_redraw(CLUTTER_ACTOR(self));
870 }
871
872 /* Theme in application has changed */
_xfdashboard_stage_theme_interface_data_free(XfdashboardStageThemeInterfaceData * inData)873 static void _xfdashboard_stage_theme_interface_data_free(XfdashboardStageThemeInterfaceData *inData)
874 {
875 g_return_if_fail(inData);
876
877 /* Release each data in data structure but do not unref the interface actor
878 * as it might be used at stage. The stage is responsible to destroy the
879 * interface actor in *any* case.
880 */
881 if(inData->focusables) g_ptr_array_unref(inData->focusables);
882 if(inData->focus) g_object_unref(inData->focus);
883
884 /* Release allocated memory */
885 g_free(inData);
886 }
887
_xfdashboard_stage_theme_interface_data_new(void)888 static XfdashboardStageThemeInterfaceData* _xfdashboard_stage_theme_interface_data_new(void)
889 {
890 XfdashboardStageThemeInterfaceData *data;
891
892 /* Allocate memory for data structure */
893 data=g_new0(XfdashboardStageThemeInterfaceData, 1);
894 if(!data) return(NULL);
895
896 /* Return newly create and initialized data structure */
897 return(data);
898 }
899
_xfdashboard_stage_on_application_theme_changed(XfdashboardStage * self,XfdashboardTheme * inTheme,gpointer inUserData)900 static void _xfdashboard_stage_on_application_theme_changed(XfdashboardStage *self,
901 XfdashboardTheme *inTheme,
902 gpointer inUserData)
903 {
904 XfdashboardStagePrivate *priv;
905 XfdashboardThemeLayout *themeLayout;
906 GList *interfaces;
907 XfdashboardStageThemeInterfaceData *interface;
908 GList *iter;
909 GList *monitors;
910 XfdashboardWindowTrackerMonitor *monitor;
911 ClutterActorIter childIter;
912 ClutterActor *child;
913 GObject *focusObject;
914 guint i;
915 gboolean reselectFocusOnResume;
916
917 g_return_if_fail(XFDASHBOARD_IS_STAGE(self));
918 g_return_if_fail(XFDASHBOARD_IS_THEME(inTheme));
919 g_return_if_fail(XFDASHBOARD_IS_APPLICATION(inUserData));
920
921 priv=self->priv;
922
923 /* Get theme layout */
924 themeLayout=xfdashboard_theme_get_layout(inTheme);
925
926 /* Create interface for each monitor if multiple monitors are supported */
927 interfaces=NULL;
928 if(xfdashboard_window_tracker_supports_multiple_monitors(priv->windowTracker))
929 {
930 monitors=xfdashboard_window_tracker_get_monitors(priv->windowTracker);
931 for(iter=monitors; iter; iter=g_list_next(iter))
932 {
933 /* Get monitor */
934 monitor=XFDASHBOARD_WINDOW_TRACKER_MONITOR(iter->data);
935
936 /* Get interface */
937 if(xfdashboard_window_tracker_monitor_is_primary(monitor))
938 {
939 /* Get interface for primary monitor */
940 interface=_xfdashboard_stage_theme_interface_data_new();
941 interface->actor=xfdashboard_theme_layout_build_interface(themeLayout,
942 XFDASHBOARD_THEME_LAYOUT_PRIMARY,
943 XFDASHBOARD_THEME_LAYOUT_BUILD_GET_FOCUSABLES, &interface->focusables,
944 XFDASHBOARD_THEME_LAYOUT_BUILD_GET_SELECTED_FOCUS, &interface->focus,
945 -1);
946 if(!interface->actor)
947 {
948 g_critical("Could not build interface '%s' from theme '%s'",
949 XFDASHBOARD_THEME_LAYOUT_PRIMARY,
950 xfdashboard_theme_get_theme_name(inTheme));
951
952 /* Release allocated resources */
953 _xfdashboard_stage_theme_interface_data_free(interface);
954 g_list_free_full(interfaces, (GDestroyNotify)_xfdashboard_stage_theme_interface_data_free);
955
956 return;
957 }
958
959 if(!XFDASHBOARD_IS_STAGE_INTERFACE(interface->actor))
960 {
961 g_critical("Interface '%s' from theme '%s' must be an actor of type %s",
962 XFDASHBOARD_THEME_LAYOUT_PRIMARY,
963 xfdashboard_theme_get_theme_name(inTheme),
964 g_type_name(XFDASHBOARD_TYPE_STAGE_INTERFACE));
965
966 /* Release allocated resources */
967 _xfdashboard_stage_theme_interface_data_free(interface);
968 g_list_free_full(interfaces, (GDestroyNotify)_xfdashboard_stage_theme_interface_data_free);
969
970 return;
971 }
972 }
973 else
974 {
975 /* Get interface for non-primary monitors. If no interface
976 * is defined in theme then create an empty interface.
977 */
978 interface=_xfdashboard_stage_theme_interface_data_new();
979 interface->actor=xfdashboard_theme_layout_build_interface(themeLayout,
980 XFDASHBOARD_THEME_LAYOUT_SECONDARY,
981 XFDASHBOARD_THEME_LAYOUT_BUILD_GET_FOCUSABLES, &interface->focusables,
982 XFDASHBOARD_THEME_LAYOUT_BUILD_GET_SELECTED_FOCUS, &interface->focus,
983 -1);
984 if(!interface->actor)
985 {
986 interface->actor=xfdashboard_stage_interface_new();
987 }
988
989 if(!XFDASHBOARD_IS_STAGE_INTERFACE(interface->actor))
990 {
991 g_critical("Interface '%s' from theme '%s' must be an actor of type %s",
992 XFDASHBOARD_THEME_LAYOUT_SECONDARY,
993 xfdashboard_theme_get_theme_name(inTheme),
994 g_type_name(XFDASHBOARD_TYPE_STAGE_INTERFACE));
995
996 /* Release allocated resources */
997 _xfdashboard_stage_theme_interface_data_free(interface);
998 g_list_free_full(interfaces, (GDestroyNotify)_xfdashboard_stage_theme_interface_data_free);
999
1000 return;
1001 }
1002 }
1003
1004 /* Set monitor at interface */
1005 xfdashboard_stage_interface_set_monitor(XFDASHBOARD_STAGE_INTERFACE(interface->actor), monitor);
1006
1007 /* Add interface to list of interfaces */
1008 interfaces=g_list_prepend(interfaces, interface);
1009 }
1010 }
1011 /* Otherwise create only a primary stage interface and set no monitor
1012 * because no one is available if multiple monitors are not supported.
1013 */
1014 else
1015 {
1016 /* Get interface for primary monitor */
1017 interface=_xfdashboard_stage_theme_interface_data_new();
1018 interface->actor=xfdashboard_theme_layout_build_interface(themeLayout,
1019 XFDASHBOARD_THEME_LAYOUT_PRIMARY,
1020 XFDASHBOARD_THEME_LAYOUT_BUILD_GET_FOCUSABLES, &interface->focusables,
1021 XFDASHBOARD_THEME_LAYOUT_BUILD_GET_SELECTED_FOCUS, &interface->focus,
1022 -1);
1023 if(!interface->actor)
1024 {
1025 g_critical("Could not build interface '%s' from theme '%s'",
1026 XFDASHBOARD_THEME_LAYOUT_PRIMARY,
1027 xfdashboard_theme_get_theme_name(inTheme));
1028
1029 /* Release allocated resources */
1030 _xfdashboard_stage_theme_interface_data_free(interface);
1031 g_list_free_full(interfaces, (GDestroyNotify)_xfdashboard_stage_theme_interface_data_free);
1032
1033 return;
1034 }
1035
1036 if(!XFDASHBOARD_IS_STAGE_INTERFACE(interface->actor))
1037 {
1038 g_critical("Interface '%s' from theme '%s' must be an actor of type %s",
1039 XFDASHBOARD_THEME_LAYOUT_PRIMARY,
1040 xfdashboard_theme_get_theme_name(inTheme),
1041 g_type_name(XFDASHBOARD_TYPE_STAGE_INTERFACE));
1042
1043 /* Release allocated resources */
1044 _xfdashboard_stage_theme_interface_data_free(interface);
1045 g_list_free_full(interfaces, (GDestroyNotify)_xfdashboard_stage_theme_interface_data_free);
1046
1047 return;
1048 }
1049
1050 /* Add interface to list of interfaces */
1051 interfaces=g_list_prepend(interfaces, interface);
1052
1053 XFDASHBOARD_DEBUG(self, ACTOR, "Creating primary interface only because of no support for multiple monitors");
1054 }
1055
1056 /* Destroy all interfaces from stage.
1057 * There is no need to reset pointer variables to quicklaunch, searchbox etc.
1058 * because they should be set NULL to by calling _xfdashboard_stage_reset_reference_on_destroy
1059 * when stage actor was destroyed.
1060 */
1061 clutter_actor_iter_init(&childIter, CLUTTER_ACTOR(self));
1062 while(clutter_actor_iter_next(&childIter, &child))
1063 {
1064 if(XFDASHBOARD_IS_STAGE_INTERFACE(child))
1065 {
1066 clutter_actor_iter_destroy(&childIter);
1067 }
1068 }
1069
1070 /* Add all new interfaces to stage */
1071 for(iter=interfaces; iter; iter=g_list_next(iter))
1072 {
1073 /* Get interface to add to stage */
1074 interface=(XfdashboardStageThemeInterfaceData*)(iter->data);
1075 if(!interface) continue;
1076
1077 /* Check for interface actor to add to stage */
1078 if(!interface->actor) continue;
1079
1080 /* Add interface to stage */
1081 clutter_actor_add_child(CLUTTER_ACTOR(self), interface->actor);
1082
1083 /* Only check children, set up pointer variables to quicklaunch, searchbox etc.
1084 * and connect signals for primary monitor.
1085 */
1086 monitor=xfdashboard_stage_interface_get_monitor(XFDASHBOARD_STAGE_INTERFACE(interface->actor));
1087 if(!monitor || xfdashboard_window_tracker_monitor_is_primary(monitor))
1088 {
1089 /* Remember primary interface */
1090 if(!priv->primaryInterface)
1091 {
1092 priv->primaryInterface=interface->actor;
1093 g_object_add_weak_pointer(G_OBJECT(priv->primaryInterface), &priv->primaryInterface);
1094 }
1095 else g_critical("Invalid multiple stages for primary monitor");
1096
1097 /* Get children from built stage and connect signals */
1098 priv->viewSelector=NULL;
1099 child=xfdashboard_find_actor_by_name(CLUTTER_ACTOR(self), "view-selector");
1100 if(child && XFDASHBOARD_IS_VIEW_SELECTOR(child))
1101 {
1102 priv->viewSelector=child;
1103 g_object_add_weak_pointer(G_OBJECT(priv->viewSelector), &priv->viewSelector);
1104
1105 /* Register this focusable actor if it is focusable */
1106 if(!interface->focusables && XFDASHBOARD_IS_FOCUSABLE(priv->viewSelector))
1107 {
1108 xfdashboard_focus_manager_register(priv->focusManager,
1109 XFDASHBOARD_FOCUSABLE(priv->viewSelector));
1110 }
1111 }
1112
1113 priv->searchbox=NULL;
1114 child=xfdashboard_find_actor_by_name(CLUTTER_ACTOR(self), "searchbox");
1115 if(child && XFDASHBOARD_IS_TEXT_BOX(child))
1116 {
1117 priv->searchbox=child;
1118 g_object_add_weak_pointer(G_OBJECT(priv->searchbox), &priv->searchbox);
1119
1120 /* If no hint-text was defined, set default one */
1121 if(!xfdashboard_text_box_is_hint_text_set(XFDASHBOARD_TEXT_BOX(priv->searchbox)))
1122 {
1123 xfdashboard_text_box_set_hint_text(XFDASHBOARD_TEXT_BOX(priv->searchbox),
1124 _("Just type to search..."));
1125 }
1126
1127 /* Connect signals */
1128 g_signal_connect_swapped(priv->searchbox,
1129 "text-changed",
1130 G_CALLBACK(_xfdashboard_stage_on_searchbox_text_changed),
1131 self);
1132 g_signal_connect_swapped(priv->searchbox,
1133 "secondary-icon-clicked",
1134 G_CALLBACK(_xfdashboard_stage_on_searchbox_secondary_icon_clicked),
1135 self);
1136
1137 /* Register this focusable actor if it is focusable */
1138 if(!interface->focusables && XFDASHBOARD_IS_FOCUSABLE(priv->searchbox))
1139 {
1140 xfdashboard_focus_manager_register(priv->focusManager,
1141 XFDASHBOARD_FOCUSABLE(priv->searchbox));
1142 }
1143 }
1144
1145 priv->viewpad=NULL;
1146 child=xfdashboard_find_actor_by_name(CLUTTER_ACTOR(self), "viewpad");
1147 if(child && XFDASHBOARD_IS_VIEWPAD(child))
1148 {
1149 priv->viewpad=child;
1150 g_object_add_weak_pointer(G_OBJECT(priv->viewpad), &priv->viewpad);
1151
1152 /* Connect signals */
1153 g_signal_connect_swapped(priv->viewpad, "view-activated", G_CALLBACK(_xfdashboard_stage_on_view_activated), self);
1154
1155 /* Register this focusable actor if it is focusable */
1156 if(!interface->focusables && XFDASHBOARD_IS_FOCUSABLE(priv->viewpad))
1157 {
1158 xfdashboard_focus_manager_register(priv->focusManager,
1159 XFDASHBOARD_FOCUSABLE(priv->viewpad));
1160
1161 /* Check if viewpad can be focused to enforce all focusable views
1162 * will be registered too. We need to do it now to get all focusable
1163 * views registered before first use of any function of focus manager.
1164 */
1165 xfdashboard_focusable_can_focus(XFDASHBOARD_FOCUSABLE(priv->viewpad));
1166 }
1167 }
1168
1169 priv->quicklaunch=NULL;
1170 child=xfdashboard_find_actor_by_name(CLUTTER_ACTOR(self), "quicklaunch");
1171 if(child && XFDASHBOARD_IS_QUICKLAUNCH(child))
1172 {
1173 XfdashboardToggleButton *appsButton;
1174
1175 priv->quicklaunch=child;
1176 g_object_add_weak_pointer(G_OBJECT(priv->quicklaunch), &priv->quicklaunch);
1177
1178 /* Connect signals */
1179 appsButton=xfdashboard_quicklaunch_get_apps_button(XFDASHBOARD_QUICKLAUNCH(priv->quicklaunch));
1180 if(appsButton)
1181 {
1182 g_signal_connect_swapped(appsButton,
1183 "toggled",
1184 G_CALLBACK(_xfdashboard_stage_on_quicklaunch_apps_button_toggled),
1185 self);
1186 }
1187
1188 /* Register this focusable actor if it is focusable */
1189 if(!interface->focusables && XFDASHBOARD_IS_FOCUSABLE(priv->quicklaunch))
1190 {
1191 xfdashboard_focus_manager_register(priv->focusManager,
1192 XFDASHBOARD_FOCUSABLE(priv->quicklaunch));
1193 }
1194 }
1195
1196 priv->workspaces=NULL;
1197 child=xfdashboard_find_actor_by_name(CLUTTER_ACTOR(self), "workspace-selector");
1198 if(child && XFDASHBOARD_IS_WORKSPACE_SELECTOR(child))
1199 {
1200 priv->workspaces=child;
1201 g_object_add_weak_pointer(G_OBJECT(priv->workspaces), &priv->workspaces);
1202
1203 /* Register this focusable actor if it is focusable */
1204 if(!interface->focusables && XFDASHBOARD_IS_FOCUSABLE(priv->workspaces))
1205 {
1206 xfdashboard_focus_manager_register(priv->focusManager,
1207 XFDASHBOARD_FOCUSABLE(priv->workspaces));
1208 }
1209 }
1210
1211 priv->notification=NULL;
1212 child=xfdashboard_find_actor_by_name(CLUTTER_ACTOR(self), "notification");
1213 if(child && XFDASHBOARD_IS_TEXT_BOX(child))
1214 {
1215 priv->notification=child;
1216 g_object_add_weak_pointer(G_OBJECT(priv->notification), &priv->notification);
1217
1218 /* Register this focusable actor if it is focusable */
1219 if(!interface->focusables && XFDASHBOARD_IS_FOCUSABLE(priv->notification))
1220 {
1221 xfdashboard_focus_manager_register(priv->focusManager,
1222 XFDASHBOARD_FOCUSABLE(priv->notification));
1223 }
1224
1225 /* Hide notification by default */
1226 clutter_actor_hide(priv->notification);
1227 clutter_actor_set_reactive(priv->notification, FALSE);
1228 }
1229
1230 priv->tooltip=NULL;
1231 child=xfdashboard_find_actor_by_name(CLUTTER_ACTOR(self), "tooltip");
1232 if(child && XFDASHBOARD_IS_TEXT_BOX(child))
1233 {
1234 priv->tooltip=child;
1235 g_object_add_weak_pointer(G_OBJECT(priv->tooltip), &priv->tooltip);
1236
1237 /* Register this focusable actor if it is focusable */
1238 if(!interface->focusables && XFDASHBOARD_IS_FOCUSABLE(priv->tooltip))
1239 {
1240 xfdashboard_focus_manager_register(priv->focusManager,
1241 XFDASHBOARD_FOCUSABLE(priv->tooltip));
1242 }
1243
1244 /* Hide tooltip by default */
1245 clutter_actor_hide(priv->tooltip);
1246 clutter_actor_set_reactive(priv->tooltip, FALSE);
1247 }
1248
1249 /* Register focusable actors at focus manager */
1250 if(interface->focusables)
1251 {
1252 for(i=0; i<interface->focusables->len; i++)
1253 {
1254 /* Get actor to register at focus manager */
1255 focusObject=G_OBJECT(g_ptr_array_index(interface->focusables, i));
1256 if(!focusObject) continue;
1257
1258 /* Check that actor is focusable */
1259 if(!XFDASHBOARD_IS_FOCUSABLE(focusObject))
1260 {
1261 g_warning("Object %s is not focusable and cannot be registered.",
1262 G_OBJECT_TYPE_NAME(focusObject));
1263 continue;
1264 }
1265
1266 /* Register actor at focus manager */
1267 xfdashboard_focus_manager_register(priv->focusManager,
1268 XFDASHBOARD_FOCUSABLE(focusObject));
1269 XFDASHBOARD_DEBUG(self, ACTOR,
1270 "Registering actor %s of interface with ID '%s' at focus manager",
1271 G_OBJECT_TYPE_NAME(focusObject),
1272 clutter_actor_get_name(interface->actor));
1273 }
1274 }
1275
1276 /* Move focus to selected actor or remember actor focus to set it later
1277 * but only if selected actor is a focusable actor and is registered
1278 * to focus manager.
1279 */
1280 if(interface->focus &&
1281 XFDASHBOARD_IS_FOCUSABLE(interface->focus) &&
1282 xfdashboard_focus_manager_is_registered(priv->focusManager, XFDASHBOARD_FOCUSABLE(interface->focus)))
1283 {
1284 /* If actor can be focused then move focus to actor ... */
1285 if(xfdashboard_focusable_can_focus(XFDASHBOARD_FOCUSABLE(interface->focus)))
1286 {
1287 xfdashboard_focus_manager_set_focus(priv->focusManager, XFDASHBOARD_FOCUSABLE(interface->focus));
1288 XFDASHBOARD_DEBUG(self, ACTOR,
1289 "Moved focus to actor %s of interface with ID '%s'",
1290 G_OBJECT_TYPE_NAME(interface->focus),
1291 clutter_actor_get_name(interface->actor));
1292
1293 /* Determine if user (also) requests to reselect focus on resume
1294 * because then remember the actor to focus to move the focus
1295 * each time the stage window gets shown after it was hidden.
1296 */
1297 reselectFocusOnResume=xfconf_channel_get_bool(xfdashboard_application_get_xfconf_channel(NULL),
1298 RESELECT_THEME_FOCUS_ON_RESUME_XFCONF_PROP,
1299 DEFAULT_RESELECT_THEME_FOCUS_ON_RESUME);
1300 if(reselectFocusOnResume)
1301 {
1302 priv->focusActorOnShow=XFDASHBOARD_FOCUSABLE(interface->focus);
1303 g_object_add_weak_pointer(G_OBJECT(priv->focusActorOnShow), &priv->focusActorOnShow);
1304
1305 XFDASHBOARD_DEBUG(self, ACTOR,
1306 "Will move focus to actor %s of interface with ID '%s' any time the stage gets visible",
1307 G_OBJECT_TYPE_NAME(interface->focus),
1308 clutter_actor_get_name(interface->actor));
1309 }
1310 }
1311 /* ... otherwise if stage is not visible, remember the actor
1312 * to focus to move the focus to it as soon as stage is
1313 * visible ...
1314 */
1315 else if(!clutter_actor_is_visible(CLUTTER_ACTOR(self)))
1316 {
1317 priv->focusActorOnShow=XFDASHBOARD_FOCUSABLE(interface->focus);
1318 g_object_add_weak_pointer(G_OBJECT(priv->focusActorOnShow), &priv->focusActorOnShow);
1319
1320 XFDASHBOARD_DEBUG(self, ACTOR,
1321 "Cannot move focus to actor %s of interface with ID '%s' but will try again when stage is visible",
1322 G_OBJECT_TYPE_NAME(interface->focus),
1323 clutter_actor_get_name(interface->actor));
1324 }
1325 /* ... otherwise just show a debug message */
1326 else
1327 {
1328 XFDASHBOARD_DEBUG(self, ACTOR,
1329 "Cannot move focus to actor %s of interface with ID '%s' because actor cannot be focused",
1330 G_OBJECT_TYPE_NAME(interface->focus),
1331 clutter_actor_get_name(interface->actor));
1332 }
1333 }
1334 else
1335 {
1336 XFDASHBOARD_DEBUG(self, ACTOR, "Cannot move focus to any actor because no one was selected in theme");
1337 }
1338 }
1339 }
1340
1341 /* Release allocated resources */
1342 g_list_free_full(interfaces, (GDestroyNotify)_xfdashboard_stage_theme_interface_data_free);
1343
1344 /* Set focus */
1345 _xfdashboard_stage_set_focus(self);
1346 }
1347
1348 /* Primary monitor changed */
_xfdashboard_stage_on_primary_monitor_changed(XfdashboardStage * self,XfdashboardWindowTrackerMonitor * inOldMonitor,XfdashboardWindowTrackerMonitor * inNewMonitor,gpointer inUserData)1349 static void _xfdashboard_stage_on_primary_monitor_changed(XfdashboardStage *self,
1350 XfdashboardWindowTrackerMonitor *inOldMonitor,
1351 XfdashboardWindowTrackerMonitor *inNewMonitor,
1352 gpointer inUserData)
1353 {
1354 XfdashboardStagePrivate *priv;
1355 XfdashboardStageInterface *oldStageInterface;
1356 XfdashboardWindowTrackerMonitor *oldPrimaryStageInterfaceMonitor;
1357 ClutterActorIter childIter;
1358 ClutterActor *child;
1359
1360 g_return_if_fail(XFDASHBOARD_IS_STAGE(self));
1361 g_return_if_fail(!inOldMonitor || XFDASHBOARD_IS_WINDOW_TRACKER_MONITOR(inOldMonitor));
1362 g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_MONITOR(inNewMonitor));
1363 g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER(inUserData));
1364
1365 priv=self->priv;
1366
1367 /* If we do not have a primary stage interface yet do nothing */
1368 if(!priv->primaryInterface) return;
1369
1370 /* If primary stage interface has already new monitor set do nothing */
1371 oldPrimaryStageInterfaceMonitor=xfdashboard_stage_interface_get_monitor(XFDASHBOARD_STAGE_INTERFACE(priv->primaryInterface));
1372 if(oldPrimaryStageInterfaceMonitor==inNewMonitor) return;
1373
1374 /* Find stage interface currently using the new primary monitor */
1375 oldStageInterface=NULL;
1376
1377 clutter_actor_iter_init(&childIter, CLUTTER_ACTOR(self));
1378 while(!oldStageInterface && clutter_actor_iter_next(&childIter, &child))
1379 {
1380 XfdashboardStageInterface *interface;
1381
1382 /* Check for stage interface */
1383 if(!XFDASHBOARD_IS_STAGE_INTERFACE(child)) continue;
1384
1385 /* Get stage interface */
1386 interface=XFDASHBOARD_STAGE_INTERFACE(child);
1387
1388 /* Check if stage interface is using new primary monitor then remember it */
1389 if(xfdashboard_stage_interface_get_monitor(interface)==inNewMonitor)
1390 {
1391 oldStageInterface=interface;
1392 }
1393 }
1394
1395 /* Set old primary monitor at stage interface which is using new primary monitor */
1396 if(oldStageInterface)
1397 {
1398 /* Set old monitor at found stage interface */
1399 xfdashboard_stage_interface_set_monitor(oldStageInterface, oldPrimaryStageInterfaceMonitor);
1400 }
1401
1402 /* Set new primary monitor at primary stage interface */
1403 xfdashboard_stage_interface_set_monitor(XFDASHBOARD_STAGE_INTERFACE(priv->primaryInterface), inNewMonitor);
1404 XFDASHBOARD_DEBUG(self, ACTOR,
1405 "Primary monitor changed from %d to %d",
1406 xfdashboard_window_tracker_monitor_get_number(oldPrimaryStageInterfaceMonitor),
1407 xfdashboard_window_tracker_monitor_get_number(inNewMonitor));
1408 }
1409
1410 /* A monitor was added */
_xfdashboard_stage_on_monitor_added(XfdashboardStage * self,XfdashboardWindowTrackerMonitor * inMonitor,gpointer inUserData)1411 static void _xfdashboard_stage_on_monitor_added(XfdashboardStage *self,
1412 XfdashboardWindowTrackerMonitor *inMonitor,
1413 gpointer inUserData)
1414 {
1415 ClutterActor *interface;
1416 XfdashboardTheme *theme;
1417 XfdashboardThemeLayout *themeLayout;
1418
1419 g_return_if_fail(XFDASHBOARD_IS_STAGE(self));
1420 g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_MONITOR(inMonitor));
1421 g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER(inUserData));
1422
1423 /* Get theme and theme layout */
1424 theme=xfdashboard_application_get_theme(NULL);
1425 themeLayout=xfdashboard_theme_get_layout(theme);
1426
1427 /* Create interface for non-primary monitors. If no interface is defined in theme
1428 * then create an empty interface.
1429 */
1430 interface=xfdashboard_theme_layout_build_interface(themeLayout, XFDASHBOARD_THEME_LAYOUT_SECONDARY);
1431 if(!interface)
1432 {
1433 interface=xfdashboard_stage_interface_new();
1434 }
1435
1436 if(!XFDASHBOARD_IS_STAGE_INTERFACE(interface))
1437 {
1438 g_critical("Interface '%s' from theme '%s' must be an actor of type %s",
1439 XFDASHBOARD_THEME_LAYOUT_SECONDARY,
1440 xfdashboard_theme_get_theme_name(theme),
1441 g_type_name(XFDASHBOARD_TYPE_STAGE_INTERFACE));
1442 return;
1443 }
1444
1445 /* Set monitor at interface */
1446 xfdashboard_stage_interface_set_monitor(XFDASHBOARD_STAGE_INTERFACE(interface), inMonitor);
1447
1448 /* Add interface to stage */
1449 clutter_actor_add_child(CLUTTER_ACTOR(self), interface);
1450 XFDASHBOARD_DEBUG(self, ACTOR,
1451 "Added stage interface for new monitor %d",
1452 xfdashboard_window_tracker_monitor_get_number(inMonitor));
1453
1454 /* If monitor added is the primary monitor then swap now the stage interfaces */
1455 if(xfdashboard_window_tracker_monitor_is_primary(inMonitor))
1456 {
1457 _xfdashboard_stage_on_primary_monitor_changed(self, NULL, inMonitor, inUserData);
1458 }
1459 }
1460
1461 /* A monitor was removed */
_xfdashboard_stage_on_monitor_removed(XfdashboardStage * self,XfdashboardWindowTrackerMonitor * inMonitor,gpointer inUserData)1462 static void _xfdashboard_stage_on_monitor_removed(XfdashboardStage *self,
1463 XfdashboardWindowTrackerMonitor *inMonitor,
1464 gpointer inUserData)
1465 {
1466 XfdashboardStagePrivate *priv;
1467 ClutterActorIter childIter;
1468 ClutterActor *child;
1469
1470 g_return_if_fail(XFDASHBOARD_IS_STAGE(self));
1471 g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_MONITOR(inMonitor));
1472 g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER(inUserData));
1473
1474 priv=self->priv;
1475
1476 /* If monitor removed is the primary monitor swap primary interface with first
1477 * stage interface to keep it alive. We should afterward receive a signal that
1478 * primary monitor has changed, then the primary interface will be set to its
1479 * right place.
1480 */
1481 if(xfdashboard_window_tracker_monitor_is_primary(inMonitor))
1482 {
1483 XfdashboardWindowTrackerMonitor* firstMonitor;
1484
1485 /* Get first monitor */
1486 firstMonitor=xfdashboard_window_tracker_get_monitor_by_number(priv->windowTracker, 0);
1487
1488 /* Swp stage interfaces */
1489 _xfdashboard_stage_on_primary_monitor_changed(self, inMonitor, firstMonitor, inUserData);
1490 }
1491
1492 /* Look up stage interface for removed monitor and destroy it */
1493 clutter_actor_iter_init(&childIter, CLUTTER_ACTOR(self));
1494 while(clutter_actor_iter_next(&childIter, &child))
1495 {
1496 XfdashboardStageInterface *interface;
1497
1498 /* Only check stage interfaces */
1499 if(!XFDASHBOARD_IS_STAGE_INTERFACE(child)) continue;
1500
1501 /* If stage interface is the one for this monitor then destroy it */
1502 interface=XFDASHBOARD_STAGE_INTERFACE(child);
1503 if(xfdashboard_stage_interface_get_monitor(interface)==inMonitor)
1504 {
1505 clutter_actor_iter_destroy(&childIter);
1506 XFDASHBOARD_DEBUG(self, ACTOR,
1507 "Removed stage interface for removed monitor %d",
1508 xfdashboard_window_tracker_monitor_get_number(inMonitor));
1509 }
1510 }
1511 }
1512
1513 /* Screen size has changed */
_xfdashboard_stage_on_screen_size_changed(XfdashboardStage * self,gpointer inUserData)1514 static void _xfdashboard_stage_on_screen_size_changed(XfdashboardStage *self,
1515 gpointer inUserData)
1516 {
1517 XfdashboardWindowTracker *windowTracker;
1518 gint screenWidth, screenHeight;
1519 gfloat stageWidth, stageHeight;
1520
1521 g_return_if_fail(XFDASHBOARD_IS_STAGE(self));
1522 g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER(inUserData));
1523
1524 windowTracker=XFDASHBOARD_WINDOW_TRACKER(inUserData);
1525
1526 /* Get screen size */
1527 xfdashboard_window_tracker_get_screen_size(windowTracker, &screenWidth, &screenHeight);
1528
1529 /* Get current size of stage */
1530 clutter_actor_get_size(CLUTTER_ACTOR(self), &stageWidth, &stageHeight);
1531
1532 /* If either stage's width or height does not match screen's width or height
1533 * resize the stage.
1534 */
1535 if((gint)stageWidth!=screenWidth ||
1536 (gint)stageHeight!=screenHeight)
1537 {
1538 XFDASHBOARD_DEBUG(self, ACTOR,
1539 "Screen resized to %dx%d but stage has size of %dx%d - resizing stage",
1540 screenWidth, screenHeight,
1541 (gint)stageWidth, (gint)stageHeight);
1542
1543 clutter_actor_set_size(CLUTTER_ACTOR(self), screenWidth, screenHeight);
1544 }
1545 }
1546
1547 /* IMPLEMENTATION: ClutterActor */
1548
1549 /* The stage actor should be shown */
_xfdashboard_stage_show(ClutterActor * inActor)1550 static void _xfdashboard_stage_show(ClutterActor *inActor)
1551 {
1552 XfdashboardStage *self;
1553 XfdashboardStagePrivate *priv;
1554 XfdashboardView *switchView;
1555
1556 g_return_if_fail(XFDASHBOARD_IS_STAGE(inActor));
1557
1558 self=XFDASHBOARD_STAGE(inActor);
1559 priv=self->priv;
1560
1561 /* Find view to switch to if requested and switch to this view */
1562 switchView=_xfdashboard_stage_get_view_to_switch_to(self);
1563 if(switchView)
1564 {
1565 xfdashboard_viewpad_set_active_view(XFDASHBOARD_VIEWPAD(priv->viewpad), switchView);
1566 }
1567
1568 /* Set stage to fullscreen as it may will be a newly created window */
1569 clutter_stage_set_fullscreen(CLUTTER_STAGE(self), TRUE);
1570
1571 /* If we do not know the stage window connect signal to find it */
1572 if(!priv->stageWindow)
1573 {
1574 /* Connect signals */
1575 XFDASHBOARD_DEBUG(self, ACTOR, "Connecting signal to find stage window");
1576 g_signal_connect_swapped(priv->windowTracker, "window-opened", G_CALLBACK(_xfdashboard_stage_on_window_opened), self);
1577 }
1578
1579 /* Call parent's show method */
1580 if(CLUTTER_ACTOR_CLASS(xfdashboard_stage_parent_class)->show)
1581 {
1582 CLUTTER_ACTOR_CLASS(xfdashboard_stage_parent_class)->show(inActor);
1583 }
1584
1585 /* Now move focus to actor is one was remembered when theme was loaded */
1586 if(priv->focusActorOnShow)
1587 {
1588 gboolean reselectFocusOnResume;
1589
1590 /* Determine if user (also) requests to reselect focus on resume */
1591 reselectFocusOnResume=xfconf_channel_get_bool(xfdashboard_application_get_xfconf_channel(NULL),
1592 RESELECT_THEME_FOCUS_ON_RESUME_XFCONF_PROP,
1593 DEFAULT_RESELECT_THEME_FOCUS_ON_RESUME);
1594
1595 /* Move focus to actor */
1596 xfdashboard_focus_manager_set_focus(priv->focusManager, XFDASHBOARD_FOCUSABLE(priv->focusActorOnShow));
1597
1598 XFDASHBOARD_DEBUG(self, ACTOR,
1599 "Moved focus to actor %s %s",
1600 G_OBJECT_TYPE_NAME(priv->focusActorOnShow),
1601 !reselectFocusOnResume ? "now as it was delayed to when stage is visible" : "because it should be reselected on resume");
1602
1603 /* Forget actor to focus now if user did not requested to reselect
1604 * this focus again and again when stage window is shown ;)
1605 */
1606 if(!reselectFocusOnResume)
1607 {
1608 g_object_remove_weak_pointer(G_OBJECT(priv->focusActorOnShow), &priv->focusActorOnShow);
1609 priv->focusActorOnShow=NULL;
1610 }
1611 }
1612 }
1613
1614 /* IMPLEMENTATION: GObject */
1615
1616 /* Dispose this object */
_xfdashboard_stage_dispose(GObject * inObject)1617 static void _xfdashboard_stage_dispose(GObject *inObject)
1618 {
1619 XfdashboardStage *self=XFDASHBOARD_STAGE(inObject);
1620 XfdashboardStagePrivate *priv=self->priv;
1621
1622 /* Release allocated resources */
1623 if(priv->stageWindow)
1624 {
1625 g_signal_handlers_disconnect_by_func(priv->stageWindow, G_CALLBACK(_xfdashboard_stage_on_window_closed), self);
1626 xfdashboard_window_tracker_window_hide_stage(priv->stageWindow);
1627 priv->stageWindow=NULL;
1628 }
1629
1630 if(priv->focusManager)
1631 {
1632 g_object_unref(priv->focusManager);
1633 priv->focusManager=NULL;
1634 }
1635
1636 if(priv->notificationTimeoutID)
1637 {
1638 g_source_remove(priv->notificationTimeoutID);
1639 priv->notificationTimeoutID=0;
1640 }
1641
1642 if(priv->windowTracker)
1643 {
1644 g_signal_handlers_disconnect_by_data(priv->windowTracker, self);
1645 g_object_unref(priv->windowTracker);
1646 priv->windowTracker=NULL;
1647 }
1648
1649 if(priv->backgroundColor)
1650 {
1651 clutter_color_free(priv->backgroundColor);
1652 priv->backgroundColor=NULL;
1653 }
1654
1655 if(priv->notification)
1656 {
1657 clutter_actor_destroy(CLUTTER_ACTOR(priv->notification));
1658 priv->notification=NULL;
1659 }
1660
1661 if(priv->tooltip)
1662 {
1663 clutter_actor_destroy(CLUTTER_ACTOR(priv->tooltip));
1664 priv->tooltip=NULL;
1665 }
1666
1667 if(priv->quicklaunch)
1668 {
1669 clutter_actor_destroy(priv->quicklaunch);
1670 priv->quicklaunch=NULL;
1671 }
1672
1673 if(priv->searchbox)
1674 {
1675 clutter_actor_destroy(priv->searchbox);
1676 priv->searchbox=NULL;
1677 }
1678
1679 if(priv->workspaces)
1680 {
1681 clutter_actor_destroy(priv->workspaces);
1682 priv->workspaces=NULL;
1683 }
1684
1685 if(priv->viewSelector)
1686 {
1687 clutter_actor_destroy(priv->viewSelector);
1688 priv->viewSelector=NULL;
1689 }
1690
1691 if(priv->viewpad)
1692 {
1693 clutter_actor_destroy(priv->viewpad);
1694 priv->viewpad=NULL;
1695 }
1696
1697 if(priv->primaryInterface)
1698 {
1699 clutter_actor_destroy(priv->primaryInterface);
1700 priv->primaryInterface=NULL;
1701 }
1702
1703 if(priv->viewBeforeSearch)
1704 {
1705 g_object_unref(priv->viewBeforeSearch);
1706 priv->viewBeforeSearch=NULL;
1707 }
1708
1709 if(priv->backgroundImageLayer)
1710 {
1711 clutter_actor_destroy(priv->backgroundImageLayer);
1712 priv->backgroundImageLayer=NULL;
1713 }
1714
1715 if(priv->backgroundColorLayer)
1716 {
1717 clutter_actor_destroy(priv->backgroundColorLayer);
1718 priv->backgroundColorLayer=NULL;
1719 }
1720
1721 if(priv->switchToView)
1722 {
1723 g_free(priv->switchToView);
1724 priv->switchToView=NULL;
1725 }
1726
1727 /* Call parent's class dispose method */
1728 G_OBJECT_CLASS(xfdashboard_stage_parent_class)->dispose(inObject);
1729 }
1730
1731 /* Set/get properties */
_xfdashboard_stage_set_property(GObject * inObject,guint inPropID,const GValue * inValue,GParamSpec * inSpec)1732 static void _xfdashboard_stage_set_property(GObject *inObject,
1733 guint inPropID,
1734 const GValue *inValue,
1735 GParamSpec *inSpec)
1736 {
1737 XfdashboardStage *self=XFDASHBOARD_STAGE(inObject);
1738
1739 switch(inPropID)
1740 {
1741 case PROP_BACKGROUND_IMAGE_TYPE:
1742 xfdashboard_stage_set_background_image_type(self, g_value_get_enum(inValue));
1743 break;
1744
1745 case PROP_BACKGROUND_COLOR:
1746 xfdashboard_stage_set_background_color(self, clutter_value_get_color(inValue));
1747 break;
1748
1749 case PROP_SWITCH_TO_VIEW:
1750 xfdashboard_stage_set_switch_to_view(self, g_value_get_string(inValue));
1751 break;
1752
1753 default:
1754 G_OBJECT_WARN_INVALID_PROPERTY_ID(inObject, inPropID, inSpec);
1755 break;
1756 }
1757 }
1758
_xfdashboard_stage_get_property(GObject * inObject,guint inPropID,GValue * outValue,GParamSpec * inSpec)1759 static void _xfdashboard_stage_get_property(GObject *inObject,
1760 guint inPropID,
1761 GValue *outValue,
1762 GParamSpec *inSpec)
1763 {
1764 XfdashboardStage *self=XFDASHBOARD_STAGE(inObject);
1765 XfdashboardStagePrivate *priv=self->priv;
1766
1767 switch(inPropID)
1768 {
1769 case PROP_BACKGROUND_IMAGE_TYPE:
1770 g_value_set_enum(outValue, priv->backgroundType);
1771 break;
1772
1773 case PROP_BACKGROUND_COLOR:
1774 clutter_value_set_color(outValue, priv->backgroundColor);
1775 break;
1776
1777 case PROP_SWITCH_TO_VIEW:
1778 g_value_set_string(outValue, priv->switchToView);
1779 break;
1780
1781 default:
1782 G_OBJECT_WARN_INVALID_PROPERTY_ID(inObject, inPropID, inSpec);
1783 break;
1784 }
1785 }
1786
1787 /* Class initialization
1788 * Override functions in parent classes and define properties
1789 * and signals
1790 */
xfdashboard_stage_class_init(XfdashboardStageClass * klass)1791 static void xfdashboard_stage_class_init(XfdashboardStageClass *klass)
1792 {
1793 ClutterActorClass *actorClass=CLUTTER_ACTOR_CLASS(klass);
1794 GObjectClass *gobjectClass=G_OBJECT_CLASS(klass);
1795
1796 /* Override functions */
1797 klass->show_tooltip=_xfdashboard_stage_show_tooltip;
1798 klass->hide_tooltip=_xfdashboard_stage_hide_tooltip;
1799
1800 actorClass->show=_xfdashboard_stage_show;
1801 actorClass->event=_xfdashboard_stage_event;
1802
1803 gobjectClass->dispose=_xfdashboard_stage_dispose;
1804 gobjectClass->set_property=_xfdashboard_stage_set_property;
1805 gobjectClass->get_property=_xfdashboard_stage_get_property;
1806
1807 /* Define properties */
1808 XfdashboardStageProperties[PROP_BACKGROUND_IMAGE_TYPE]=
1809 g_param_spec_enum("background-image-type",
1810 "Background image type",
1811 "Background image type",
1812 XFDASHBOARD_TYPE_STAGE_BACKGROUND_IMAGE_TYPE,
1813 XFDASHBOARD_STAGE_BACKGROUND_IMAGE_TYPE_NONE,
1814 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1815
1816 XfdashboardStageProperties[PROP_BACKGROUND_COLOR]=
1817 clutter_param_spec_color("background-color",
1818 "Background color",
1819 "Color of stage's background",
1820 NULL,
1821 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1822
1823 XfdashboardStageProperties[PROP_SWITCH_TO_VIEW]=
1824 g_param_spec_string("switch-to-view",
1825 "Switch to view",
1826 "Switch to this named view as soon as stage gets visible",
1827 NULL,
1828 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
1829
1830 g_object_class_install_properties(gobjectClass, PROP_LAST, XfdashboardStageProperties);
1831
1832 /* Define signals */
1833 XfdashboardStageSignals[SIGNAL_ACTOR_CREATED]=
1834 g_signal_new("actor-created",
1835 G_TYPE_FROM_CLASS(klass),
1836 G_SIGNAL_RUN_LAST,
1837 G_STRUCT_OFFSET(XfdashboardStageClass, actor_created),
1838 NULL,
1839 NULL,
1840 g_cclosure_marshal_VOID__OBJECT,
1841 G_TYPE_NONE,
1842 1,
1843 CLUTTER_TYPE_ACTOR);
1844
1845 XfdashboardStageSignals[SIGNAL_SEARCH_STARTED]=
1846 g_signal_new("search-started",
1847 G_TYPE_FROM_CLASS(klass),
1848 G_SIGNAL_RUN_LAST,
1849 G_STRUCT_OFFSET(XfdashboardStageClass, search_started),
1850 NULL,
1851 NULL,
1852 g_cclosure_marshal_VOID__VOID,
1853 G_TYPE_NONE,
1854 0);
1855
1856 XfdashboardStageSignals[SIGNAL_SEARCH_CHANGED]=
1857 g_signal_new("search-changed",
1858 G_TYPE_FROM_CLASS(klass),
1859 G_SIGNAL_RUN_LAST,
1860 G_STRUCT_OFFSET(XfdashboardStageClass, search_changed),
1861 NULL,
1862 NULL,
1863 g_cclosure_marshal_VOID__STRING,
1864 G_TYPE_NONE,
1865 1,
1866 G_TYPE_STRING);
1867
1868 XfdashboardStageSignals[SIGNAL_SEARCH_ENDED]=
1869 g_signal_new("search-ended",
1870 G_TYPE_FROM_CLASS(klass),
1871 G_SIGNAL_RUN_LAST,
1872 G_STRUCT_OFFSET(XfdashboardStageClass, search_ended),
1873 NULL,
1874 NULL,
1875 g_cclosure_marshal_VOID__VOID,
1876 G_TYPE_NONE,
1877 0);
1878
1879 XfdashboardStageSignals[SIGNAL_SHOW_TOOLTIP]=
1880 g_signal_new("show-tooltip",
1881 G_TYPE_FROM_CLASS(klass),
1882 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1883 G_STRUCT_OFFSET(XfdashboardStageClass, show_tooltip),
1884 NULL,
1885 NULL,
1886 g_cclosure_marshal_VOID__OBJECT,
1887 G_TYPE_NONE,
1888 1,
1889 CLUTTER_TYPE_ACTION);
1890
1891 XfdashboardStageSignals[SIGNAL_HIDE_TOOLTIP]=
1892 g_signal_new("hide-tooltip",
1893 G_TYPE_FROM_CLASS(klass),
1894 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
1895 G_STRUCT_OFFSET(XfdashboardStageClass, hide_tooltip),
1896 NULL,
1897 NULL,
1898 g_cclosure_marshal_VOID__OBJECT,
1899 G_TYPE_NONE,
1900 1,
1901 CLUTTER_TYPE_ACTION);
1902 }
1903
1904 /* Object initialization
1905 * Create private structure and set up default values
1906 */
xfdashboard_stage_init(XfdashboardStage * self)1907 static void xfdashboard_stage_init(XfdashboardStage *self)
1908 {
1909 XfdashboardStagePrivate *priv;
1910 XfdashboardApplication *application;
1911 ClutterConstraint *widthConstraint;
1912 ClutterConstraint *heightConstraint;
1913 ClutterColor transparent;
1914
1915 priv=self->priv=xfdashboard_stage_get_instance_private(self);
1916
1917 /* Set default values */
1918 priv->focusManager=xfdashboard_focus_manager_get_default();
1919 priv->windowTracker=xfdashboard_window_tracker_get_default();
1920 priv->stageWindow=NULL;
1921 priv->primaryInterface=NULL;
1922 priv->quicklaunch=NULL;
1923 priv->searchbox=NULL;
1924 priv->workspaces=NULL;
1925 priv->viewpad=NULL;
1926 priv->viewSelector=NULL;
1927 priv->notification=NULL;
1928 priv->tooltip=NULL;
1929 priv->lastSearchTextLength=0;
1930 priv->viewBeforeSearch=NULL;
1931 priv->searchActive=FALSE;
1932 priv->notificationTimeoutID=0;
1933 priv->backgroundType=XFDASHBOARD_STAGE_BACKGROUND_IMAGE_TYPE_NONE;
1934 priv->backgroundColor=NULL;
1935 priv->backgroundColorLayer=NULL;
1936 priv->backgroundImageLayer=NULL;
1937 priv->switchToView=NULL;
1938 priv->focusActorOnShow=NULL;
1939
1940 /* Create background actors but order of adding background children is important */
1941 widthConstraint=clutter_bind_constraint_new(CLUTTER_ACTOR(self), CLUTTER_BIND_WIDTH, 0.0f);
1942 heightConstraint=clutter_bind_constraint_new(CLUTTER_ACTOR(self), CLUTTER_BIND_HEIGHT, 0.0f);
1943 priv->backgroundImageLayer=clutter_actor_new();
1944 clutter_actor_hide(priv->backgroundImageLayer);
1945 clutter_actor_add_constraint(priv->backgroundImageLayer, widthConstraint);
1946 clutter_actor_add_constraint(priv->backgroundImageLayer, heightConstraint);
1947 clutter_actor_add_child(CLUTTER_ACTOR(self), priv->backgroundImageLayer);
1948
1949 widthConstraint=clutter_bind_constraint_new(CLUTTER_ACTOR(self), CLUTTER_BIND_WIDTH, 0.0f);
1950 heightConstraint=clutter_bind_constraint_new(CLUTTER_ACTOR(self), CLUTTER_BIND_HEIGHT, 0.0f);
1951 priv->backgroundColorLayer=clutter_actor_new();
1952 clutter_actor_hide(priv->backgroundColorLayer);
1953 clutter_actor_add_constraint(priv->backgroundColorLayer, widthConstraint);
1954 clutter_actor_add_constraint(priv->backgroundColorLayer, heightConstraint);
1955 clutter_actor_add_child(CLUTTER_ACTOR(self), priv->backgroundColorLayer);
1956
1957 /* Set up stage and style it */
1958 clutter_color_init(&transparent, 0, 0, 0, 0);
1959 clutter_actor_set_background_color(CLUTTER_ACTOR(self), &transparent);
1960
1961 clutter_stage_set_use_alpha(CLUTTER_STAGE(self), TRUE);
1962 clutter_stage_set_user_resizable(CLUTTER_STAGE(self), FALSE);
1963 clutter_stage_set_fullscreen(CLUTTER_STAGE(self), TRUE);
1964
1965 /* Connect signals to window tracker */
1966 g_signal_connect_swapped(priv->windowTracker,
1967 "monitor-added",
1968 G_CALLBACK(_xfdashboard_stage_on_monitor_added),
1969 self);
1970 g_signal_connect_swapped(priv->windowTracker,
1971 "monitor-removed",
1972 G_CALLBACK(_xfdashboard_stage_on_monitor_removed),
1973 self);
1974 g_signal_connect_swapped(priv->windowTracker,
1975 "primary-monitor-changed",
1976 G_CALLBACK(_xfdashboard_stage_on_primary_monitor_changed),
1977 self);
1978
1979 /* Connect signal to application */
1980 application=xfdashboard_application_get_default();
1981 g_signal_connect_swapped(application,
1982 "suspend",
1983 G_CALLBACK(_xfdashboard_stage_on_application_suspend),
1984 self);
1985
1986 g_signal_connect_swapped(application,
1987 "resume",
1988 G_CALLBACK(_xfdashboard_stage_on_application_resume),
1989 self);
1990
1991 g_signal_connect_swapped(application,
1992 "theme-changed",
1993 G_CALLBACK(_xfdashboard_stage_on_application_theme_changed),
1994 self);
1995
1996 /* Resize stage to match screen size and listen for futher screen size changes
1997 * to resize stage again.
1998 * This should only be needed when compiled against Clutter prior to 0.17.2
1999 * because this version or newer ones seem to handle window resizes correctly.
2000 */
2001 if(clutter_major_version<1 ||
2002 (clutter_major_version==1 && clutter_minor_version<17) ||
2003 (clutter_major_version==1 && clutter_minor_version==17 && clutter_micro_version<2))
2004 {
2005 _xfdashboard_stage_on_screen_size_changed(self, priv->windowTracker);
2006
2007 g_signal_connect_swapped(priv->windowTracker,
2008 "screen-size-changed",
2009 G_CALLBACK(_xfdashboard_stage_on_screen_size_changed),
2010 self);
2011
2012 XFDASHBOARD_DEBUG(self, ACTOR, "Tracking screen resizes to resize stage");
2013 }
2014 }
2015
2016 /* IMPLEMENTATION: Public API */
2017
2018 /* Create new instance */
xfdashboard_stage_new(void)2019 ClutterActor* xfdashboard_stage_new(void)
2020 {
2021 return(CLUTTER_ACTOR(g_object_new(XFDASHBOARD_TYPE_STAGE, NULL)));
2022 }
2023
2024 /* Get/set background type */
xfdashboard_stage_get_background_image_type(XfdashboardStage * self)2025 XfdashboardStageBackgroundImageType xfdashboard_stage_get_background_image_type(XfdashboardStage *self)
2026 {
2027 g_return_val_if_fail(XFDASHBOARD_IS_STAGE(self), XFDASHBOARD_STAGE_BACKGROUND_IMAGE_TYPE_NONE);
2028
2029 return(self->priv->backgroundType);
2030 }
2031
xfdashboard_stage_set_background_image_type(XfdashboardStage * self,XfdashboardStageBackgroundImageType inType)2032 void xfdashboard_stage_set_background_image_type(XfdashboardStage *self, XfdashboardStageBackgroundImageType inType)
2033 {
2034 XfdashboardStagePrivate *priv;
2035
2036 g_return_if_fail(XFDASHBOARD_IS_STAGE(self));
2037 g_return_if_fail(inType<=XFDASHBOARD_STAGE_BACKGROUND_IMAGE_TYPE_DESKTOP);
2038
2039 priv=self->priv;
2040
2041
2042 /* Set value if changed */
2043 if(priv->backgroundType!=inType)
2044 {
2045 /* Set value */
2046 priv->backgroundType=inType;
2047
2048 /* Set up background actor depending on type */
2049 if(priv->backgroundImageLayer)
2050 {
2051 switch(priv->backgroundType)
2052 {
2053 case XFDASHBOARD_STAGE_BACKGROUND_IMAGE_TYPE_DESKTOP:
2054 {
2055 XfdashboardWindowTrackerWindow *backgroundWindow;
2056
2057 backgroundWindow=xfdashboard_window_tracker_get_root_window(priv->windowTracker);
2058 if(backgroundWindow)
2059 {
2060 ClutterContent *backgroundContent;
2061
2062 backgroundContent=xfdashboard_window_tracker_window_get_content(backgroundWindow);
2063 clutter_actor_show(priv->backgroundImageLayer);
2064 clutter_actor_set_content(priv->backgroundImageLayer, backgroundContent);
2065 g_object_unref(backgroundContent);
2066
2067 XFDASHBOARD_DEBUG(self, ACTOR, "Desktop window was found and set up as background image for stage");
2068 }
2069 else
2070 {
2071 g_signal_connect_swapped(priv->windowTracker,
2072 "window-opened",
2073 G_CALLBACK(_xfdashboard_stage_on_desktop_window_opened),
2074 self);
2075 XFDASHBOARD_DEBUG(self, ACTOR, "Desktop window was not found. Setting up signal to get notified when desktop window might be opened.");
2076 }
2077 }
2078 break;
2079
2080 default:
2081 clutter_actor_hide(priv->backgroundImageLayer);
2082 clutter_actor_set_content(priv->backgroundImageLayer, NULL);
2083 break;
2084 }
2085 }
2086
2087 /* Notify about property change */
2088 g_object_notify_by_pspec(G_OBJECT(self), XfdashboardStageProperties[PROP_BACKGROUND_IMAGE_TYPE]);
2089 }
2090 }
2091
2092 /* Get/set background color */
xfdashboard_stage_get_background_color(XfdashboardStage * self)2093 ClutterColor* xfdashboard_stage_get_background_color(XfdashboardStage *self)
2094 {
2095 g_return_val_if_fail(XFDASHBOARD_IS_STAGE(self), NULL);
2096
2097 return(self->priv->backgroundColor);
2098 }
2099
xfdashboard_stage_set_background_color(XfdashboardStage * self,const ClutterColor * inColor)2100 void xfdashboard_stage_set_background_color(XfdashboardStage *self, const ClutterColor *inColor)
2101 {
2102 XfdashboardStagePrivate *priv;
2103
2104 g_return_if_fail(XFDASHBOARD_IS_STAGE(self));
2105
2106 priv=self->priv;
2107
2108 /* Set value if changed */
2109 if((priv->backgroundColor && !inColor) ||
2110 (!priv->backgroundColor && inColor) ||
2111 (inColor && clutter_color_equal(inColor, priv->backgroundColor)==FALSE))
2112 {
2113 /* Set value */
2114 if(priv->backgroundColor)
2115 {
2116 clutter_color_free(priv->backgroundColor);
2117 priv->backgroundColor=NULL;
2118 }
2119
2120 if(inColor) priv->backgroundColor=clutter_color_copy(inColor);
2121
2122 /* If a color is provided set background color and show background actor
2123 * otherwise hide background actor
2124 */
2125 if(priv->backgroundColorLayer)
2126 {
2127 if(priv->backgroundColor)
2128 {
2129 clutter_actor_set_background_color(priv->backgroundColorLayer,
2130 priv->backgroundColor);
2131 clutter_actor_show(priv->backgroundColorLayer);
2132 }
2133 else clutter_actor_hide(priv->backgroundColorLayer);
2134 }
2135
2136 /* Notify about property change */
2137 g_object_notify_by_pspec(G_OBJECT(self), XfdashboardStageProperties[PROP_BACKGROUND_COLOR]);
2138 }
2139 }
2140
2141 /* Set name of view to switch to at next resume */
xfdashboard_stage_get_switch_to_view(XfdashboardStage * self)2142 const gchar* xfdashboard_stage_get_switch_to_view(XfdashboardStage *self)
2143 {
2144 g_return_val_if_fail(XFDASHBOARD_IS_STAGE(self), NULL);
2145
2146 return(self->priv->switchToView);
2147 }
2148
xfdashboard_stage_set_switch_to_view(XfdashboardStage * self,const gchar * inViewInternalName)2149 void xfdashboard_stage_set_switch_to_view(XfdashboardStage *self, const gchar *inViewInternalName)
2150 {
2151 XfdashboardStagePrivate *priv;
2152
2153 g_return_if_fail(XFDASHBOARD_IS_STAGE(self));
2154
2155 priv=self->priv;
2156
2157 /* Set value if changed */
2158 if(g_strcmp0(priv->switchToView, inViewInternalName)!=0)
2159 {
2160 if(priv->switchToView)
2161 {
2162 g_free(priv->switchToView);
2163 priv->switchToView=NULL;
2164 }
2165
2166 if(inViewInternalName) priv->switchToView=g_strdup(inViewInternalName);
2167
2168 /* Notify about property change */
2169 g_object_notify_by_pspec(G_OBJECT(self), XfdashboardStageProperties[PROP_SWITCH_TO_VIEW]);
2170 }
2171 }
2172
2173 /* Show a notification on stage */
xfdashboard_stage_show_notification(XfdashboardStage * self,const gchar * inIconName,const gchar * inText)2174 void xfdashboard_stage_show_notification(XfdashboardStage *self, const gchar *inIconName, const gchar *inText)
2175 {
2176 XfdashboardStagePrivate *priv;
2177 gint interval;
2178
2179 g_return_if_fail(XFDASHBOARD_IS_STAGE(self));
2180
2181 priv=self->priv;
2182
2183 /* Stop current running timeout source because it would hide this
2184 * new notification to soon.
2185 */
2186 if(priv->notificationTimeoutID)
2187 {
2188 g_source_remove(priv->notificationTimeoutID);
2189 priv->notificationTimeoutID=0;
2190 }
2191
2192 /* Only show notification if a notification box is known where the notification
2193 * could be shown at.
2194 */
2195 if(!priv->notification)
2196 {
2197 XFDASHBOARD_DEBUG(self, ACTOR, "Cannot show notification because no notification box is available");
2198 return;
2199 }
2200
2201 /* Show notification on stage */
2202 xfdashboard_text_box_set_text(XFDASHBOARD_TEXT_BOX(priv->notification), inText);
2203 xfdashboard_text_box_set_primary_icon(XFDASHBOARD_TEXT_BOX(priv->notification), inIconName);
2204 clutter_actor_show(CLUTTER_ACTOR(priv->notification));
2205
2206 /* Set up timeout source. The timeout interval differs and depends on the length
2207 * of the notification text to show but never drops below the minimum timeout configured.
2208 * The interval is calculated by one second for 30 characters.
2209 */
2210 interval=xfconf_channel_get_uint(xfdashboard_application_get_xfconf_channel(NULL),
2211 NOTIFICATION_TIMEOUT_XFCONF_PROP,
2212 DEFAULT_NOTIFICATION_TIMEOUT);
2213 interval=MAX((gint)((strlen(inText)/30.0f)*1000.0f), interval);
2214
2215 priv->notificationTimeoutID=clutter_threads_add_timeout_full(G_PRIORITY_DEFAULT,
2216 interval,
2217 _xfdashboard_stage_on_notification_timeout,
2218 self,
2219 _xfdashboard_stage_on_notification_timeout_destroyed);
2220 }
2221