/* Remove a window from application tracker item if it exists */ static gboolean _xfdashboard_application_tracker_item_remove_window(XfdashboardApplicationTrackerItem *inItem, XfdashboardWindowTrackerWindow *inWindow) { GList *iter; XfdashboardWindowTrackerWindow *window; g_return_val_if_fail(inItem, FALSE); g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW(inWindow), FALSE); /* Iterate through list of windows for application tracker item and if window * was found remove it from list of windows and return immediately. */ for(iter=inItem->windows; iter; iter=g_list_next(iter)) { /* Get window */ window=(XfdashboardWindowTrackerWindow*)iter->data; if(!window) continue; /* Check if window we are iterating right now is the one to lookup */ if(window==inWindow) { inItem->windows=g_list_delete_link(inItem->windows, iter); return(TRUE); } } /* If we get here the window to remove was not found, so return FALSE here */ return(FALSE); }
/* Find live window actor by window */ static ClutterActor* _xfdashboard_live_workspace_find_by_window(XfdashboardLiveWorkspace *self, XfdashboardWindowTrackerWindow *inWindow) { ClutterActor *child; ClutterActorIter iter; ClutterContent *content; XfdashboardWindowTrackerWindow *window; g_return_val_if_fail(XFDASHBOARD_IS_LIVE_WORKSPACE(self), NULL); g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW(inWindow), NULL); /* Iterate through list of current actors and find the one for requested window */ clutter_actor_iter_init(&iter, CLUTTER_ACTOR(self)); while(clutter_actor_iter_next(&iter, &child)) { content=clutter_actor_get_content(child); if(!content || !XFDASHBOARD_IS_WINDOW_CONTENT(content)) continue; window=xfdashboard_window_content_get_window(XFDASHBOARD_WINDOW_CONTENT(content)); if(window==inWindow) return(child); } /* If we get here we did not find the window and we return NULL */ return(NULL); }
/* A window's workspace has changed */ static void _xfdashboard_live_workspace_on_window_workspace_changed(XfdashboardLiveWorkspace *self, XfdashboardWindowTrackerWindow *inWindow, XfdashboardWindowTrackerWorkspace *inWorkspace, gpointer inUserData) { XfdashboardLiveWorkspacePrivate *priv; ClutterActor *windowActor; g_return_if_fail(XFDASHBOARD_IS_LIVE_WORKSPACE(self)); g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW(inWindow)); priv=self->priv; /* Check if window was removed from workspace or added */ if(inWorkspace!=priv->workspace) { /* Find actor for window */ windowActor=_xfdashboard_live_workspace_find_by_window(self, inWindow); /* Destroy window actor */ if(windowActor) clutter_actor_destroy(windowActor); } else { /* Add window actor */ _xfdashboard_live_workspace_create_and_add_window_actor(self, inWindow); } }
/* The active window has changed */ static void _xfdashboard_application_tracker_on_active_window_changed(XfdashboardApplicationTracker *self, XfdashboardWindowTrackerWindow *inOldActiveWindow, XfdashboardWindowTrackerWindow *inNewActiveWindow, gpointer inUserData) { XfdashboardApplicationTrackerItem *item; g_return_if_fail(XFDASHBOARD_IS_APPLICATION_TRACKER(self)); g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW(inNewActiveWindow)); /* Find application tracker item in list of known running applications * matching the new active window. */ item= _xfdashboard_application_tracker_find_item_by_window(self, inNewActiveWindow); if(!item) { g_debug("Could not find running application for new active window '%s'", xfdashboard_window_tracker_window_get_title(inNewActiveWindow)); return; } g_debug("New active window is '%s' and belongs to desktop ID '%s'", xfdashboard_window_tracker_window_get_title(inNewActiveWindow), item->desktopID); /* Move new active window of found application tracker item to begin of * list of windows by removing window from list and prepending it to list * again. This will sort the list of window in order of last activation. * That means the first window in list was the last active one for this * application. */ item->windows=g_list_remove(item->windows, inNewActiveWindow); item->windows=g_list_prepend(item->windows, inNewActiveWindow); }
/* Add a window to application tracker item but avoid duplicates */ static gboolean _xfdashboard_application_tracker_item_add_window(XfdashboardApplicationTrackerItem *inItem, XfdashboardWindowTrackerWindow *inWindow) { GList *iter; XfdashboardWindowTrackerWindow *window; g_return_val_if_fail(inItem, FALSE); g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW(inWindow), FALSE); /* Iterate through list of windows for application tracker item and return * immediately if requested window to add is found in list. */ for(iter=inItem->windows; iter; iter=g_list_next(iter)) { /* Get window */ window=(XfdashboardWindowTrackerWindow*)iter->data; if(!window) continue; /* Check if window we are iterating right now is the one to lookup */ if(window==inWindow) return(FALSE); } /* If we get here the window was not found in list of windows of application * tracker item, so add it to beginning of this list as it should be the * last active windows for this application. */ inItem->windows=g_list_prepend(inItem->windows, inWindow); /* Return TRUE as window was added */ return(TRUE); }
/* A window's position and/or size has changed */ static void _xfdashboard_live_workspace_on_window_geometry_changed(XfdashboardLiveWorkspace *self, XfdashboardWindowTrackerWindow *inWindow, gpointer inUserData) { g_return_if_fail(XFDASHBOARD_IS_LIVE_WORKSPACE(self)); g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW(inWindow)); /* Actor's allocation may change because of new geometry so relayout */ clutter_actor_queue_relayout(CLUTTER_ACTOR(self)); }
/* A window was created */ static void _xfdashboard_application_tracker_on_window_opened(XfdashboardApplicationTracker *self, XfdashboardWindowTrackerWindow *inWindow, gpointer inUserData) { XfdashboardApplicationTrackerPrivate *priv; GAppInfo *appInfo; XfdashboardApplicationTrackerItem *item; g_return_if_fail(XFDASHBOARD_IS_APPLICATION_TRACKER(self)); g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW(inWindow)); priv=self->priv; appInfo=NULL; /* Try to find application for window */ appInfo=_xfdashboard_application_tracker_get_desktop_id_from_environment(self, inWindow); if(!appInfo) appInfo=_xfdashboard_application_tracker_get_desktop_id_from_window_names(self, inWindow); /* If we could not resolve window to a desktop application info, then stop here */ if(!appInfo) { g_debug("Could not resolve window '%s' to any desktop ID", xfdashboard_window_tracker_window_get_title(inWindow)); return; } g_debug("Window '%s' belongs to desktop ID '%s'", xfdashboard_window_tracker_window_get_title(inWindow), g_app_info_get_id(appInfo)); /* Create application tracker if no one exists for application and window ... */ item= _xfdashboard_application_tracker_find_item_by_app_info(self, appInfo); if(!item) { /* Create application tracker item */ item=_xfdashboard_application_tracker_item_new(appInfo, inWindow); /* Add new item to list of running applications */ priv->runningApps=g_list_prepend(priv->runningApps, item); /* Emit signal as this application is known to be running now */ g_debug("Emitting signal 'state-changed' to running for desktop ID '%s'", item->desktopID); g_signal_emit(self, XfdashboardApplicationTrackerSignals[SIGNAL_STATE_CHANGED], g_quark_from_string(item->desktopID), item->desktopID, TRUE); } /* ... otherwise add window to existing one */ else { /* Add window to list of window for known running application */ _xfdashboard_application_tracker_item_add_window(item, inWindow); } /* Release allocated resources */ if(appInfo) g_object_unref(appInfo); }
/* A window was closed */ static void _xfdashboard_live_workspace_on_window_closed(XfdashboardLiveWorkspace *self, XfdashboardWindowTrackerWindow *inWindow, gpointer inUserData) { ClutterActor *windowActor; g_return_if_fail(XFDASHBOARD_IS_LIVE_WORKSPACE(self)); g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW(inWindow)); /* Find and destroy actor */ windowActor=_xfdashboard_live_workspace_find_by_window(self, inWindow); if(windowActor) clutter_actor_destroy(windowActor); }
/* A window was opened */ static void _xfdashboard_live_workspace_on_window_opened(XfdashboardLiveWorkspace *self, XfdashboardWindowTrackerWindow *inWindow, gpointer inUserData) { g_return_if_fail(XFDASHBOARD_IS_LIVE_WORKSPACE(self)); g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW(inWindow)); /* Check if window is visible on this workspace */ if(!_xfdashboard_live_workspace_is_visible_window(self, inWindow)) return; /* Create actor for window */ _xfdashboard_live_workspace_create_and_add_window_actor(self, inWindow); }
/* Create new application tracker item */ static XfdashboardApplicationTrackerItem* _xfdashboard_application_tracker_item_new(GAppInfo *inAppInfo, XfdashboardWindowTrackerWindow *inWindow) { XfdashboardApplicationTrackerItem *item; g_return_val_if_fail(G_IS_APP_INFO(inAppInfo), NULL); g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW(inWindow), NULL); /* Create new application item and set up */ item=g_new0(XfdashboardApplicationTrackerItem, 1); item->pid=xfdashboard_window_tracker_window_get_pid(inWindow); item->appInfo=g_object_ref(inAppInfo); item->desktopID=g_strdup(g_app_info_get_id(inAppInfo)); item->windows=g_list_prepend(item->windows, inWindow); /* Return newly created application tracker item */ return(item); }
/* Check if window should be shown */ static gboolean _xfdashboard_live_workspace_is_visible_window(XfdashboardLiveWorkspace *self, XfdashboardWindowTrackerWindow *inWindow) { XfdashboardLiveWorkspacePrivate *priv; g_return_val_if_fail(XFDASHBOARD_IS_LIVE_WORKSPACE(self), FALSE); g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW(inWindow), FALSE); priv=self->priv; /* Determine if windows should be shown depending on its state */ if(xfdashboard_window_tracker_window_is_skip_pager(inWindow) || xfdashboard_window_tracker_window_is_skip_tasklist(inWindow) || (priv->workspace && !xfdashboard_window_tracker_window_is_visible_on_workspace(inWindow, priv->workspace)) || xfdashboard_window_tracker_window_is_stage(inWindow)) { return(FALSE); } /* If we get here the window should be shown */ return(TRUE); }
/* Find application tracker item by window */ static XfdashboardApplicationTrackerItem* _xfdashboard_application_tracker_find_item_by_window(XfdashboardApplicationTracker *self, XfdashboardWindowTrackerWindow *inWindow) { XfdashboardApplicationTrackerPrivate *priv; GList *appIter; g_return_val_if_fail(XFDASHBOARD_IS_APPLICATION_TRACKER(self), NULL); g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW(inWindow), NULL); priv=self->priv; /* Iterate through list of window of each application tracker item and * lookup item owning the requested window. */ for(appIter=priv->runningApps; appIter; appIter=g_list_next(appIter)) { XfdashboardApplicationTrackerItem *item; GList *windowIter; XfdashboardWindowTrackerWindow *window; /* Get application tracker item */ item=(XfdashboardApplicationTrackerItem*)appIter->data; if(!item) continue; /* Iterate through list of known window for item */ for(windowIter=item->windows; windowIter; windowIter=g_list_next(windowIter)) { /* Get window */ window=(XfdashboardWindowTrackerWindow*)windowIter->data; if(!window) continue; /* Check if window we are iterating right now is the one to lookup */ if(window==inWindow) return(item); } } /* If we get here no item owns requested window */ return(NULL); }
/* A window's state has changed */ static void _xfdashboard_live_workspace_on_window_state_changed(XfdashboardLiveWorkspace *self, XfdashboardWindowTrackerWindow *inWindow, gpointer inUserData) { /* We need to see it from the point of view of a workspace. * If a window is visible on the workspace but we have no actor * for this window then create it. If a window is not visible anymore * on this workspace then destroy the corresponding actor. * That is why initially we set any window to invisible because if * changed window is not visible on this workspace it will do nothing. */ ClutterActor *windowActor; gboolean newVisible; gboolean currentVisible; g_return_if_fail(XFDASHBOARD_IS_LIVE_WORKSPACE(self)); g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW(inWindow)); currentVisible=FALSE; /* Find window and get current visibility state */ windowActor=_xfdashboard_live_workspace_find_by_window(self, inWindow); if(windowActor) { currentVisible=!!CLUTTER_ACTOR_IS_VISIBLE(windowActor); } /* Check if window's visibility has changed */ newVisible=_xfdashboard_live_workspace_is_visible_window(self, inWindow); if(newVisible!=currentVisible) { if(newVisible) _xfdashboard_live_workspace_create_and_add_window_actor(self, inWindow); else if(windowActor) clutter_actor_destroy(windowActor); } }
/* Get desktop ID from window names. * Callee is responsible to free result with g_object_unref(). */ static GAppInfo* _xfdashboard_application_tracker_get_desktop_id_from_window_names(XfdashboardApplicationTracker *self, XfdashboardWindowTrackerWindow *inWindow) { XfdashboardApplicationTrackerPrivate *priv; GAppInfo *foundAppInfo; gchar **names; gchar **iter; GList *apps; g_return_val_if_fail(XFDASHBOARD_IS_APPLICATION_TRACKER(self), NULL); g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW(inWindow), NULL); priv=self->priv; foundAppInfo=NULL; /* Get list of applications */ apps=xfdashboard_application_database_get_all_applications(priv->appDatabase); /* Get window's names */ names=xfdashboard_window_tracker_window_get_instance_names(inWindow); /* Iterate through window's names to try to find matching desktop file */ iter=names; while(iter && *iter) { GAppInfo *appInfo; gchar *iterName; gchar *iterNameLowerCase; /* Build desktop ID from iterated name */ if(!g_str_has_suffix(*iter, ".desktop")) iterName=g_strconcat(*iter, ".desktop", NULL); else iterName=g_strdup(*iter); iterNameLowerCase=g_utf8_strdown(iterName, -1); /* Lookup application from unmodified name */ appInfo=xfdashboard_application_database_lookup_desktop_id(priv->appDatabase, iterName); /* Lookup application from to-lower-case converted name if previous * lookup with unmodified name failed. */ if(!appInfo) { /* Lookup application from lower-case name */ appInfo=xfdashboard_application_database_lookup_desktop_id(priv->appDatabase, iterNameLowerCase); } /* If no application was found for the name it may be an application * located in a subdirectory. Then the desktop ID is prefixed with * the subdirectory's name followed by a dash. So iterate through all * applications and lookup with glob pattern '*-' followed by name * and suffix '.desktop'. */ if(!appInfo) { GList *iterApps; GList *foundSubdirApps; gchar *globName; GPatternSpec *globPattern; GAppInfo *globAppInfo; /* Build glob pattern */ globAppInfo=NULL; globName=g_strconcat("*-", iterNameLowerCase, NULL); globPattern=g_pattern_spec_new(globName); /* Iterate through application and collect applications matching * glob pattern. */ foundSubdirApps=NULL; for(iterApps=apps; iterApps; iterApps=g_list_next(iterApps)) { if(!G_IS_APP_INFO(iterApps->data)) continue; globAppInfo=G_APP_INFO(iterApps->data); if(g_pattern_match_string(globPattern, g_app_info_get_id(globAppInfo))) { foundSubdirApps=g_list_prepend(foundSubdirApps, globAppInfo); g_debug("Found possible application '%s' for window '%s' using pattern '%s'", g_app_info_get_id(globAppInfo), xfdashboard_window_tracker_window_get_title(inWindow), globName); } } /* If exactly one application was collected because it matched * the glob pattern then we found the application. */ if(g_list_length(foundSubdirApps)==1) { appInfo=G_APP_INFO(g_object_ref(G_OBJECT(foundSubdirApps->data))); g_debug("Found exactly one application named '%s' for window '%s' using pattern '%s'", g_app_info_get_id(appInfo), xfdashboard_window_tracker_window_get_title(inWindow), globName); } /* Release allocated resources */ if(foundSubdirApps) g_list_free(foundSubdirApps); if(globPattern) g_pattern_spec_free(globPattern); if(globName) g_free(globName); } /* If we still did not find an application continue with next * name in list. */ if(!appInfo) { /* Release allocated resources */ if(iterName) g_free(iterName); if(iterNameLowerCase) g_free(iterNameLowerCase); /* Continue with next name in list */ iter++; continue; } /* Check if found application info matches previous one. If it does not match * the desktop IDs found previously are ambigous, so return NULL result. */ if(foundAppInfo && !g_app_info_equal(foundAppInfo, appInfo)) { g_debug("Resolved window names of '%s' are ambiguous - discarding desktop IDs '%s' and '%s'", xfdashboard_window_tracker_window_get_title(inWindow), g_app_info_get_id(foundAppInfo), g_app_info_get_id(appInfo)); /* Release allocated resources */ if(iterName) g_free(iterName); if(iterNameLowerCase) g_free(iterNameLowerCase); if(foundAppInfo) g_object_unref(foundAppInfo); if(appInfo) g_object_unref(appInfo); if(names) g_strfreev(names); if(apps) g_list_free_full(apps, g_object_unref); return(NULL); } /* If it is the first application info found, remember it */ if(!foundAppInfo) foundAppInfo=g_object_ref(appInfo); /* Release allocated resources */ if(iterName) g_free(iterName); if(iterNameLowerCase) g_free(iterNameLowerCase); if(appInfo) g_object_unref(appInfo); /* Continue with next name in list */ iter++; } /* Release allocated resources */ if(names) g_strfreev(names); if(apps) g_list_free_full(apps, g_object_unref); /* Return found application info */ g_debug("Resolved window names of '%s' to desktop ID '%s'", xfdashboard_window_tracker_window_get_title(inWindow), foundAppInfo ? g_app_info_get_id(foundAppInfo) : "<nil>"); return(foundAppInfo); }
/* A window was closed */ static void _xfdashboard_application_tracker_on_window_closed(XfdashboardApplicationTracker *self, XfdashboardWindowTrackerWindow *inWindow, gpointer inUserData) { XfdashboardApplicationTrackerPrivate *priv; XfdashboardApplicationTrackerItem *item; g_return_if_fail(XFDASHBOARD_IS_APPLICATION_TRACKER(self)); g_return_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW(inWindow)); priv=self->priv; /* Find application tracker item in list of known running applications * matching the window just closed. */ item= _xfdashboard_application_tracker_find_item_by_window(self, inWindow); if(!item) { g_debug("Could not find running application for window '%s'", xfdashboard_window_tracker_window_get_title(inWindow)); return; } g_debug("Closing window '%s' for desktop ID '%s'", xfdashboard_window_tracker_window_get_title(inWindow), item->desktopID); /* Remove window from found application tracker item */ _xfdashboard_application_tracker_item_remove_window(item, inWindow); /* If it was the last window then application is not running anymore * because it has no window. */ if(!item->windows || g_list_length(item->windows)==0) { gchar *desktopID; g_debug("Closing window '%s' for desktop ID '%s' closed last window so remove application from list of running ones", xfdashboard_window_tracker_window_get_title(inWindow), item->desktopID); /* Create a copy of desktop ID for signal emission because the * application tracker item will be removed and freed before. */ desktopID=g_strdup(item->desktopID); /* Remove application tracker item from list of running applications * and free it. */ priv->runningApps=g_list_remove(priv->runningApps, item); _xfdashboard_application_tracker_item_free(item); /* Emit signal as this application is not running anymore */ g_debug("Emitting signal 'state-changed' to stopped for desktop ID '%s'", desktopID); g_signal_emit(self, XfdashboardApplicationTrackerSignals[SIGNAL_STATE_CHANGED], g_quark_from_string(desktopID), desktopID, FALSE); /* Release allocated resources */ g_free(desktopID); } }
/* Get desktop ID from window names. * Callee is responsible to free result with g_object_unref(). */ static GAppInfo* _xfdashboard_application_tracker_get_desktop_id_from_window_names(XfdashboardApplicationTracker *self, XfdashboardWindowTrackerWindow *inWindow) { XfdashboardApplicationTrackerPrivate *priv; GAppInfo *foundAppInfo; gchar **names; gchar **iter; g_return_val_if_fail(XFDASHBOARD_IS_APPLICATION_TRACKER(self), NULL); g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW(inWindow), NULL); priv=self->priv; foundAppInfo=NULL; /* Get window's names */ names=xfdashboard_window_tracker_window_get_instance_names(inWindow); /* Iterate through window's names to try to find matching desktop file */ iter=names; while(iter && *iter) { GAppInfo *appInfo; /* Lookup application from unmodified name */ if(g_str_has_suffix(*iter, ".desktop")) { appInfo=xfdashboard_application_database_lookup_desktop_id(priv->appDatabase, *iter); } else { gchar *desktopID; desktopID=g_strconcat(*iter, ".desktop", NULL); appInfo=xfdashboard_application_database_lookup_desktop_id(priv->appDatabase, desktopID); g_free(desktopID); } /* Lookup application from to-lower-case converted name if previous * lookup with unmodified name failed. */ if(!appInfo) { gchar *lowerDesktopID; /* Convert name to lower case */ lowerDesktopID=g_utf8_strdown(*iter, -1); /* Lookup application from lower-case name. No need to add '.desktop' * as suffix as it was done before. */ if(g_str_has_suffix(lowerDesktopID, ".desktop")) { appInfo=xfdashboard_application_database_lookup_desktop_id(priv->appDatabase, lowerDesktopID); } else { gchar *desktopID; desktopID=g_strconcat(lowerDesktopID, ".desktop", NULL); appInfo=xfdashboard_application_database_lookup_desktop_id(priv->appDatabase, desktopID); g_free(desktopID); } /* Free lower case of name */ g_free(lowerDesktopID); /* If we still did not find an application continue with next * name in list. */ if(!appInfo) { /* Continue with next name in list */ iter++; continue; } } /* Check if found application info matches previous one. If it does not match * the desktop IDs found previously are ambigous, so return NULL result. */ if(foundAppInfo && !g_app_info_equal(foundAppInfo, appInfo)) { g_debug("Resolved window names of '%s' are ambiguous - discarding desktop IDs '%s' and '%s'", xfdashboard_window_tracker_window_get_title(inWindow), g_app_info_get_id(foundAppInfo), g_app_info_get_id(appInfo)); /* Release allocated resources */ if(foundAppInfo) g_object_unref(foundAppInfo); if(appInfo) g_object_unref(appInfo); if(names) g_strfreev(names); return(NULL); } /* If it is the first application info found, remember it */ if(!foundAppInfo) foundAppInfo=g_object_ref(appInfo); /* Release allocated resources */ if(appInfo) g_object_unref(appInfo); /* Continue with next name in list */ iter++; } /* Release allocated resources */ if(names) g_strfreev(names); /* Return found application info */ g_debug("Resolved window names of '%s' to desktop ID '%s'", xfdashboard_window_tracker_window_get_title(inWindow), foundAppInfo ? g_app_info_get_id(foundAppInfo) : "<nil>"); return(foundAppInfo); }
/* Get desktop ID from process' environment which owns window. * Callee is responsible to free result with g_object_unref(). */ static GAppInfo* _xfdashboard_application_tracker_get_desktop_id_from_environment(XfdashboardApplicationTracker *self, XfdashboardWindowTrackerWindow *inWindow) { XfdashboardApplicationTrackerPrivate *priv; GAppInfo *foundAppInfo; gint windowPID; gchar *procEnvFile; gchar *envContent; gsize envLength; GError *error; gchar *iter; const gchar *gioLaunchedPID; const gchar *gioLaunchedDesktopFile; g_return_val_if_fail(XFDASHBOARD_IS_APPLICATION_TRACKER(self), NULL); g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW(inWindow), NULL); priv=self->priv; foundAppInfo=NULL; error=NULL; /* Get process ID running this window */ windowPID=xfdashboard_window_tracker_window_get_pid(inWindow); if(windowPID<=0) { g_debug("Could not get PID for window '%s' of a running application to parse environment variables", xfdashboard_window_tracker_window_get_title(inWindow)); return(NULL); } /* Open enviroment variables of process. * This is the initial set of environment variables set when process was spawned. * But that is ok because the environment variables we lookup are set * at launch time and do not change. */ envContent=NULL; envLength=0; procEnvFile=g_strdup_printf("/proc/%d/environ", windowPID); if(!g_file_get_contents(procEnvFile, &envContent, &envLength, &error)) { g_debug("Could read in enviroment varibles for PID %d of window '%s' at %s: %s", windowPID, xfdashboard_window_tracker_window_get_title(inWindow), procEnvFile, error ? error->message : _("Unknown error")); /* Release allocated resources */ if(error) g_error_free(error); if(procEnvFile) g_free(procEnvFile); if(envContent) g_free(envContent); /* Return NULL result */ return(NULL); } g_debug("Enviroment set at %s is %lu bytes long for window '%s'", procEnvFile, envLength, xfdashboard_window_tracker_window_get_title(inWindow)); /* Iterate through enviroment variables and lookup GIO_LAUNCHED_DESKTOP_FILE * and GIO_LAUNCHED_DESKTOP_FILE_PID. */ gioLaunchedPID=NULL; gioLaunchedDesktopFile=NULL; iter=envContent; while(envLength>0) { gsize len; /* Skip NULL-termination */ if(!*iter) { envLength--; iter++; continue; } /* Check current iterated enviroment variable matches a requested one */ if(g_str_has_prefix(iter, "GIO_LAUNCHED_DESKTOP_FILE=")) { /* Each enviroment variable should be listed only once * otherwise is an error. */ if(gioLaunchedDesktopFile) { g_debug("Could parse in enviroment varibles for PID %d of window '%s' at %s because GIO_LAUNCHED_DESKTOP_FILE exists more than once", windowPID, xfdashboard_window_tracker_window_get_title(inWindow), procEnvFile); /* Release allocated resources */ if(foundAppInfo) g_object_unref(foundAppInfo); if(procEnvFile) g_free(procEnvFile); if(envContent) g_free(envContent); /* Return NULL result */ return(NULL); } /* Remember value of environment variable */ gioLaunchedDesktopFile=iter; } else if(g_str_has_prefix(iter, "GIO_LAUNCHED_DESKTOP_FILE_PID=")) { /* Each enviroment variable should be listed only once * otherwise is an error. */ if(gioLaunchedPID) { g_debug("Could parse in enviroment varibles for PID %d of window '%s' at %s because GIO_LAUNCHED_DESKTOP_FILE_PID exists more than once", windowPID, xfdashboard_window_tracker_window_get_title(inWindow), procEnvFile); /* Release allocated resources */ if(foundAppInfo) g_object_unref(foundAppInfo); if(procEnvFile) g_free(procEnvFile); if(envContent) g_free(envContent); /* Return NULL result */ return(NULL); } /* Remember value of environment variable */ gioLaunchedPID=iter; } /* If all requested environment variable has been found stop iterating */ if(gioLaunchedPID && gioLaunchedDesktopFile) break; /* Continue with next environment variable */ len=strlen(iter); iter+=len; envLength-=len; } /* If all requested environment variable has been found then check if * GIO_LAUNCHED_DESKTOP_FILE_PID matches window owner's process ID. */ if(gioLaunchedPID && gioLaunchedDesktopFile) { /* Move pointer of environment variables to value */ while(*gioLaunchedPID && *gioLaunchedPID!='=') gioLaunchedPID++; while(*gioLaunchedDesktopFile && *gioLaunchedDesktopFile!='=') gioLaunchedDesktopFile++; /* Check if pointers points to value assignment character */ if(*gioLaunchedPID=='=' && *gioLaunchedDesktopFile=='=') { gint checkPID; /* Move pointer one byte further where value begins really */ gioLaunchedPID++; gioLaunchedDesktopFile++; /* Check if PID of enviroment variable matches window owner's * process ID. */ checkPID=atoi(gioLaunchedPID); if(checkPID==windowPID) { /* Lookup application from full path */ foundAppInfo=xfdashboard_application_database_lookup_desktop_id(priv->appDatabase, gioLaunchedDesktopFile); if(!foundAppInfo) { /* Lookup application from basename of path */ gioLaunchedDesktopFile=g_strrstr(gioLaunchedDesktopFile, G_DIR_SEPARATOR_S); if(gioLaunchedDesktopFile) { gioLaunchedDesktopFile++; foundAppInfo=xfdashboard_application_database_lookup_desktop_id(priv->appDatabase, gioLaunchedDesktopFile); } } } else { g_debug("PID %d of environment variable does not match window PID %d for '%s'", checkPID, windowPID, xfdashboard_window_tracker_window_get_title(inWindow)); } } } /* Release allocated resources */ if(procEnvFile) g_free(procEnvFile); if(envContent) g_free(envContent); /* Return found application info */ g_debug("Resolved enviroment variables of window '%s' to desktop ID '%s'", xfdashboard_window_tracker_window_get_title(inWindow), foundAppInfo ? g_app_info_get_id(foundAppInfo) : "<nil>"); return(foundAppInfo); }
/* Create actor for window but respect window stacking when adding */ static ClutterActor* _xfdashboard_live_workspace_create_and_add_window_actor(XfdashboardLiveWorkspace *self, XfdashboardWindowTrackerWindow *inWindow) { XfdashboardLiveWorkspacePrivate *priv; ClutterActor *actor; ClutterContent *content; GList *windows; ClutterActor *lastWindowActor; XfdashboardWindowTrackerWindow *window; g_return_val_if_fail(XFDASHBOARD_IS_LIVE_WORKSPACE(self), NULL); g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW(inWindow), NULL); priv=self->priv; /* We cannot assume that each window newly opened or moved to this workspace * will be on top of all other windows. We need to respect window stacking. * Therefore we iterate through list of windows in stacking order and find * the last window we have an actor for before we the window requested. */ lastWindowActor=NULL; windows=xfdashboard_window_tracker_get_windows_stacked(priv->windowTracker); for( ; windows; windows=g_list_next(windows)) { /* Get window from list */ window=XFDASHBOARD_WINDOW_TRACKER_WINDOW(windows->data); if(!window) continue; /* We do not need to check if window would be visible on this workspace * as it should not have been created if it is not visible. */ lastWindowActor=_xfdashboard_live_workspace_find_by_window(self, window); if(lastWindowActor) break; } /* Check if we have to "move" an existing window actor or if we have to create * a new actor for window */ actor=_xfdashboard_live_workspace_find_by_window(self, inWindow); if(actor) { /* Move existing window actor to new stacking position */ g_object_ref(actor); clutter_actor_remove_child(CLUTTER_ACTOR(self), actor); clutter_actor_insert_child_above(CLUTTER_ACTOR(self), actor, lastWindowActor); g_object_unref(actor); } else { /* Create actor */ actor=clutter_actor_new(); content=xfdashboard_window_content_new_for_window(inWindow); clutter_actor_set_content(actor, content); g_object_unref(content); /* Add new actor at right stacking position */ clutter_actor_insert_child_above(CLUTTER_ACTOR(self), actor, lastWindowActor); } return(actor); }
/* Get desktop ID from process' environment which owns window. * Callee is responsible to free result with g_object_unref(). */ static GAppInfo* _xfdashboard_application_tracker_get_desktop_id_from_environment(XfdashboardApplicationTracker *self, XfdashboardWindowTrackerWindow *inWindow) { XfdashboardApplicationTrackerPrivate *priv; GAppInfo *foundAppInfo; gint windowPID; GHashTable *environments; gchar *value; gint checkPID; g_return_val_if_fail(XFDASHBOARD_IS_APPLICATION_TRACKER(self), NULL); g_return_val_if_fail(XFDASHBOARD_IS_WINDOW_TRACKER_WINDOW(inWindow), NULL); priv=self->priv; foundAppInfo=NULL; /* Get process ID running this window */ windowPID=xfdashboard_window_tracker_window_get_pid(inWindow); if(windowPID<=0) { g_debug("Could not get PID for window '%s' of a running application to parse environment variables", xfdashboard_window_tracker_window_get_title(inWindow)); /* Return NULL result */ return(NULL); } /* Get hash-table with environment variables found for window's PID */ environments=_xfdashboard_application_tracker_get_environment_from_pid(windowPID); if(!environments) { g_debug("Could not get environments for PID %d of windows '%s'", windowPID, xfdashboard_window_tracker_window_get_title(inWindow)); /* Return NULL result */ return(NULL); } /* Check that environment variable GIO_LAUNCHED_DESKTOP_FILE_PID exists. * Also check that the PID in value matches the requested window's PID * as the process may inherit the environments of its parent process * but then this one is not the initial process for this application. */ if(!g_hash_table_lookup_extended(environments, "GIO_LAUNCHED_DESKTOP_FILE_PID", NULL, (gpointer)&value)) { g_debug("Missing 'GIO_LAUNCHED_DESKTOP_FILE_PID' in environment variables for PID %d of windows '%s'", windowPID, xfdashboard_window_tracker_window_get_title(inWindow)); /* Release allocated resources */ if(environments) g_hash_table_destroy(environments); /* Return NULL result */ return(NULL); } checkPID=atoi(value); if(checkPID!=windowPID) { g_debug("PID %d of environment variables does not match requested window PID %d for '%s'", checkPID, windowPID, xfdashboard_window_tracker_window_get_title(inWindow)); /* Release allocated resources */ if(environments) g_hash_table_destroy(environments); /* Return NULL result */ return(NULL); } /* Check that environment variable GIO_LAUNCHED_DESKTOP_FILE exists and * lookup application from full path as set in environment's value. */ if(!g_hash_table_lookup_extended(environments, "GIO_LAUNCHED_DESKTOP_FILE", NULL, (gpointer)&value)) { g_debug("Missing 'GIO_LAUNCHED_DESKTOP_FILE' in environment variables for PID %d of windows '%s'", windowPID, xfdashboard_window_tracker_window_get_title(inWindow)); /* Release allocated resources */ if(environments) g_hash_table_destroy(environments); /* Return NULL result */ return(NULL); } foundAppInfo=xfdashboard_application_database_lookup_desktop_id(priv->appDatabase, value); if(!foundAppInfo) { /* Lookup application from basename of path */ value=g_strrstr(value, G_DIR_SEPARATOR_S); if(value) { value++; foundAppInfo=xfdashboard_application_database_lookup_desktop_id(priv->appDatabase, value); } } /* Release allocated resources */ if(environments) g_hash_table_destroy(environments); /* Return found application info which may be NULL if not found in * application database. */ g_debug("Resolved enviroment variables of window '%s' to desktop ID '%s'", xfdashboard_window_tracker_window_get_title(inWindow), foundAppInfo ? g_app_info_get_id(foundAppInfo) : "<nil>"); return(foundAppInfo); }