GFile *cur_image_file; /* Cached list of images in the same folder as image_path */
GList *image_files;
GList *used_image_files; /* monitor for the image_files directory */
GFileMonitor *monitor;
};
static gboolean
xfdesktop_g_file_equal0(GFile *a, GFile *b) { if (a != NULL && b != NULL) { return g_file_equal(a, b);
} else { return a == NULL && b == NULL;
}
}
/* we compare by the collate key so the image listing is the same as how
* xfdesktop-settings displays the images */ static gint
glist_compare_by_file_collate_key(GFile *a, GFile *b) {
gint ret;
gchar *a_key = g_utf8_collate_key_for_filename(g_file_peek_path(a), -1);
gchar *b_key = g_utf8_collate_key_for_filename(g_file_peek_path(b), -1);
if (!xfdesktop_g_file_equal0(cycler->cur_image_file, image_file)) { if (cycler->cur_image_file != NULL) {
g_object_unref(cycler->cur_image_file);
}
cycler->cur_image_file = g_object_ref(image_file);
}
// Usually we'd only do the following stuff if the file name hadn't // changed, but we use this path to reload things when the name hasn't // changed, but the file contents have been rewritten.
gchar *property_name = g_strconcat(cycler->property_prefix, "/last-image", NULL);
g_signal_handlers_block_by_func(cycler->channel,
xfdesktop_backdrop_cycler_image_filename_changed,
cycler);
xfconf_channel_set_string(cycler->channel, property_name, g_file_peek_path(cycler->cur_image_file));
g_signal_handlers_unblock_by_func(cycler->channel,
xfdesktop_backdrop_cycler_image_filename_changed,
cycler);
switch (event) { case G_FILE_MONITOR_EVENT_CREATED: if (!xfdesktop_backdrop_cycler_is_enabled(cycler)) { /* If we're not cycling, do nothing, it's faster :) */ break;
}
/* Make sure we don't already have the new file in the list */ if (g_list_find_custom(cycler->image_files, file, (GCompareFunc)xfdesktop_g_file_compare) != NULL
|| g_list_find_custom(cycler->used_image_files, file, (GCompareFunc)xfdesktop_g_file_compare) != NULL)
{ return;
}
/* If the new file is not an image then we don't have to do
* anything */ if (!xfdesktop_image_file_is_valid(file)) { return;
}
if (!cycler->random_order) { /* It is an image file and we don't have it in our list, add *itsortedtoourlist,don'tfreechangedfile,thatwill
* happen when it is removed */
cycler->image_files = g_list_insert_sorted(cycler->image_files,
g_object_ref(file),
(GCompareFunc)glist_compare_by_file_collate_key);
} else { /* Same as above except we don't care about the list's order
* so just add it */
cycler->image_files = g_list_prepend(cycler->image_files, g_object_ref(file));
}
if (cycler->timer_id == 0 && xfdesktop_backdrop_cycler_is_enabled(cycler)) {
xfdesktop_backdrop_cycler_set_timer(cycler, cycler->timer);
}
break;
case G_FILE_MONITOR_EVENT_DELETED: if (!xfdesktop_backdrop_cycler_is_enabled(cycler)) { /* If we're not cycling, do nothing, it's faster :) */ break;
}
/* find the file in the list */
GList **found_list = &cycler->image_files;
item = g_list_find_custom(cycler->image_files,
file,
(GCompareFunc)xfdesktop_g_file_compare); if (item == NULL) {
found_list = &cycler->used_image_files;
item = g_list_find_custom(cycler->used_image_files,
file,
(GCompareFunc)xfdesktop_g_file_compare);
}
/* remove it */ if (item) {
g_object_unref(item->data);
*found_list = g_list_delete_link(*found_list, item);
}
if (cycler->image_files == NULL && cycler->used_image_files == NULL) { if (cycler->timer_id != 0) {
g_source_remove(cycler->timer_id);
cycler->timer_id = 0;
}
}
break;
default: break;
}
}
/* Equivalent to (except for not being a stable sort), but faster than
* g_list_sort(list, (GCompareFunc)glist_compare_by_file_collate_key) */ static GList *
sort_image_list(GList *list, guint list_size) {
KeyFilePair *array;
guint i;
GList *l;
/* Allocate an array of the same size as list */
array = g_malloc(list_size * sizeof(array[0]));
/* Copy list contents to the array and generate collation keys */ for (l = list, i = 0; l; l = l->next, ++i) {
GFile *file = G_FILE(l->data);
array[i].file = file;
array[i].key = g_utf8_collate_key_for_filename(g_file_peek_path(file), -1);
}
/* Sort the array */
qsort(array, list_size, sizeof(array[0]), qsort_compare_pair_by_key);
/* Copy sorted array back to the list and deallocate the collation keys */ for (l = list, i = 0; l; l = l->next, ++i) {
l->data = array[i].file;
g_free(array[i].key);
}
g_free(array);
#if TEST_IMAGE_SORTING
list2 = g_list_sort(list2, (GCompareFunc)glist_compare_by_file_collate_key); if (g_list_length(list) != g_list_length(list2)) {
printf("Image sorting test FAILED: list size is not correct.");
} else {
GList *l2;
gboolean data_matches = TRUE, pointers_match = TRUE; for (l = list, l2 = list2; l; l = l->next, l2 = l2->next) { if (!g_file_equal(l->data, l2->data)) {
data_matches = FALSE;
} if (l->data != l2->data) {
pointers_match = FALSE;
}
} if (data_matches) {
printf("Image sorting test SUCCEEDED: "); if (pointers_match) {
printf("both data and pointers are correct.");
} else {
printf("data matches but pointers do not match. " "This is caused by unstable sorting.");
}
} else {
printf("Image sorting test FAILED: "); if (pointers_match) {
printf("data does not match but pointers do match. " "Something went really wrong!");
} else {
printf("neither data nor pointers match.");
}
}
}
putchar('\n'); #endif
return list;
}
/* Returns a GList of all the image files in the parent directory of filename */ static GList *
list_image_files_in_dir(XfdesktopBackdropCycler *cycler, GFile *file) {
GList *files = NULL;
guint file_count = 0;
/* Only sort if there's more than 1 item and we're not randomly picking
* images from the list */ if (file_count > 1 && !cycler->random_order) {
files = sort_image_list(files, file_count);
}
/* generate the image_files list if it doesn't exist and we're cycling
* backdrops */ if (cycler->image_files == NULL
&& cycler->used_image_files == NULL
&& xfdesktop_backdrop_cycler_is_enabled(cycler))
{
xfdesktop_backdrop_clear_directory_monitor(cycler);
cycler->image_files = list_image_files_in_dir(cycler, cycler->cur_image_file);
}
/* Always monitor the directory even if we aren't cycling so we know if
* our current wallpaper has changed by an external program/script */ if (cycler->image_style != XFCE_BACKDROP_IMAGE_NONE && cycler->cur_image_file != NULL && cycler->monitor == NULL) {
GFile *parent = g_file_get_parent(cycler->cur_image_file);
/* monitor the directory for changes */
cycler->monitor = g_file_monitor(parent, G_FILE_MONITOR_NONE, NULL, NULL);
g_signal_connect(cycler->monitor, "changed",
G_CALLBACK(cb_xfdesktop_backdrop_cycler_image_files_changed),
cycler);
/* Gets the next valid image file in the folder. Free when done using it
* returns NULL on fail. */ static GFile *
xfdesktop_backdrop_cycler_choose_next(XfdesktopBackdropCycler *cycler) {
TRACE("entering");
/* Get the our current background in the list */
GList *cur_link = g_list_find_custom(cycler->image_files,
cycler->cur_image_file,
(GCompareFunc)xfdesktop_g_file_compare);
/* if somehow we don't have a valid file, grab the first one available */ if (cur_link == NULL) {
cur_link = g_list_first(cycler->image_files);
} else { /* We want the next valid image file in the dir */
cur_link = g_list_next(cur_link);
/* we hit the end of the list, wrap around to the front */ if (cur_link == NULL) {
cur_link = g_list_first(cycler->image_files);
}
}
/* return a copy of our new item */ return G_FILE(cur_link->data);
}
/* Gets a random valid image file in the folder. Free when done using it.
* returns NULL on fail. */ static GFile *
xfdesktop_backdrop_cycler_choose_random(XfdesktopBackdropCycler *cycler) {
gint n_items = 0, cur_file;
/* Provides a mapping of image files in the parent folder of file. It selects *theimagebasedonthehourofthedayscaledforhowmanyimagesarein *thedirectory,usingthefirst24iftherearemore.
* Returns a new image path or NULL on failure. Free when done using it. */ static GFile *
xfdesktop_backdrop_cycler_choose_chronological(XfdesktopBackdropCycler *cycler) {
GDateTime *datetime;
GList *new_file;
gint n_items = 0, epoch;
/* If there's only 1 item, just return it, easy */ if (1 == n_items) { return G_FILE(g_list_first(cycler->image_files)->data);
}
datetime = g_date_time_new_now_local();
/* Figure out which image to display based on what time of day it is
* and how many images we have to work with */
epoch = (gdouble)g_date_time_get_hour(datetime) / (24.0f / MIN(n_items, 24.0f));
XF_DEBUG("epoch %d, hour %d, items %d", epoch, g_date_time_get_hour(datetime), n_items);
if (cycler->period == XFCE_BACKDROP_PERIOD_CHRONOLOGICAL) { /* chronological first */
new_backdrop = xfdesktop_backdrop_cycler_choose_chronological(cycler);
} elseif (cycler->random_order) { /* then random */
new_backdrop = xfdesktop_backdrop_cycler_choose_random(cycler);
} else { /* sequential, the default */
new_backdrop = xfdesktop_backdrop_cycler_choose_next(cycler);
}
/* Only emit the cycle signal if something changed */ if (new_backdrop != NULL) {
xfdesktop_backdrop_cycler_update_image_file(cycler, new_backdrop);
}
}
}
/* Don't bother with trying to cycle a cycler if we're not using images */ if (cycler->image_style != XFCE_BACKDROP_IMAGE_NONE) {
xfdesktop_backdrop_cycler_do_cycle(cycler);
}
/* Now to complicate things; we have to handle some special cases */
guint new_cycle_interval = 0; switch (cycler->period) { case XFCE_BACKDROP_PERIOD_STARTUP: /* no more cycling */ returnFALSE;
case XFCE_BACKDROP_PERIOD_CHRONOLOGICAL: case XFCE_BACKDROP_PERIOD_HOURLY: {
GDateTime *local_time = g_date_time_new_now_local();
gint minute = g_date_time_get_minute(local_time);
gint second = g_date_time_get_second(local_time);
/* find out how long until the next hour so we cycle on the hour */
new_cycle_interval = ((59 - minute) * 60) + (60 - second);
g_date_time_unref(local_time); break;
}
case XFCE_BACKDROP_PERIOD_DAILY: {
GDateTime *local_time = g_date_time_new_now_local();
gint hour = g_date_time_get_hour (local_time);
gint minute = g_date_time_get_minute(local_time);
gint second = g_date_time_get_second(local_time);
/* find out how long until the next day so we cycle on the day */
new_cycle_interval = ((23 - hour) * 60 * 60) + ((59 - minute) * 60) + (60 - second);
g_date_time_unref(local_time); break;
}
default: /* no changes required */ break;
}
/* Update the timer if we're trying to keep things on the hour/day */ if (new_cycle_interval != 0) {
xfdesktop_backdrop_cycler_remove_backdrop_timer(cycler);
/* Don't do anything if the filename doesn't change */ if (xfdesktop_g_file_equal0(cycler->cur_image_file, file)) { if (file != NULL) {
g_object_unref(file);
} return;
}
/* We need to free the image_files if image_path changed directories */ if (cycler->image_files != NULL || cycler->used_image_files != NULL || cycler->monitor != NULL) { if (cycler->cur_image_file != NULL) {
old_dir = g_file_get_parent(cycler->cur_image_file);
} if (file != NULL) {
new_dir = g_file_get_parent(file);
}
/* Directories did change */ if (!xfdesktop_g_file_equal0(old_dir, new_dir)) { /* Free the image list if we had one */
g_list_free_full(cycler->image_files, g_object_unref);
cycler->image_files = NULL;
g_list_free_full(cycler->used_image_files, g_object_unref);
cycler->used_image_files = NULL;
/* release the directory monitor */
xfdesktop_backdrop_clear_directory_monitor(cycler);
}
switch (cycler->period) { case XFCE_BACKDROP_PERIOD_SECONDS:
cycle_interval = cycler->timer; break;
case XFCE_BACKDROP_PERIOD_MINUTES:
cycle_interval = cycler->timer * 60; break;
case XFCE_BACKDROP_PERIOD_HOURS:
cycle_interval = cycler->timer * 60 * 60; break;
case XFCE_BACKDROP_PERIOD_CHRONOLOGICAL: case XFCE_BACKDROP_PERIOD_STARTUP: /* Startup and chronological will be triggered at once */
cycle_interval = 1; break;
case XFCE_BACKDROP_PERIOD_HOURLY: {
GDateTime *local_time = g_date_time_new_now_local();
gint minute = g_date_time_get_minute(local_time);
gint second = g_date_time_get_second(local_time);
/* find out how long until the next hour so we cycle on the hour */
cycle_interval = ((59 - minute) * 60) + (60 - second);
g_date_time_unref(local_time); break;
}
case XFCE_BACKDROP_PERIOD_DAILY: {
GDateTime *local_time = g_date_time_new_now_local();
gint hour = g_date_time_get_hour (local_time);
gint minute = g_date_time_get_minute(local_time);
gint second = g_date_time_get_second(local_time);
/* find out how long until the next day so we cycle on the day */
cycle_interval = ((23 - hour) * 60 * 60) + ((59 - minute) * 60) + (60 - second);
g_date_time_unref(local_time); break;
}
if (cycler->random_order != random_order) {
cycler->random_order = random_order;
/* If we have an image list and care about order now, sort the list */ if (!random_order) { if (cycler->used_image_files != NULL) {
cycler->image_files = g_list_concat(cycler->image_files, cycler->used_image_files);
cycler->used_image_files = NULL;
}
staticvoid
xfdesktop_backdrop_cycler_image_filename_changed(XfconfChannel *channel, const gchar *property_name, const GValue *value,
XfdesktopBackdropCycler *cycler)
{
TRACE("entering"); // This callback handles external changes, like if the user changes the // filename in the settings UI. If _we_ change the filename because it's // time to cycle, we block this signal handler temporarily. if (G_VALUE_HOLDS_STRING(value)) {
xfdesktop_backdrop_cycler_set_image_filename(cycler, g_value_get_string(value)); // If the user has selected a new file manually, reset the timer.
xfdesktop_backdrop_cycler_set_timer(cycler, cycler->timer);
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.