void eventd_nd_notification_draw(EventdNdNotification *self, cairo_surface_t *surface) { gint padding; gint offset_y = 0; gdouble value = -1; padding = eventd_nd_style_get_bubble_padding(self->style); switch ( eventd_nd_style_get_text_valign(self->style) ) { case EVENTD_ND_VANCHOR_BOTTOM: offset_y = self->content_size.height - self->text.height; break; case EVENTD_ND_VANCHOR_CENTER: offset_y = self->content_size.height / 2 - self->text.height / 2; break; case EVENTD_ND_VANCHOR_TOP: break; } if ( self->event != NULL ) { GVariant *val; val = eventd_event_get_data(self->event, eventd_nd_style_get_template_progress(self->style)); if ( val != NULL ) value = g_variant_get_double(val); if ( eventd_nd_style_get_progress_reversed(self->style) ) value = 1.0 - value; } cairo_t *cr; cr = cairo_create(surface); eventd_nd_draw_bubble_draw(cr, self->style, self->bubble_size.width, self->bubble_size.height, self->context->shaping, value); cairo_translate(cr, padding, padding); eventd_nd_draw_image_and_icon_draw(cr, self->image, self->icon, self->style, self->content_size.width, self->content_size.height, value); eventd_nd_draw_text_draw(cr, self->style, self->text.text, self->text.x, offset_y); cairo_destroy(cr); cairo_surface_flush(surface); }
const gchar * _eventd_config_get_best_match(GList *list, EventdEvent *event, GQuark *current_flags) { GList *match_; for ( match_ = list ; match_ != NULL ; match_ = g_list_next(match_) ) { EventdConfigMatch *match = match_->data; gboolean skip = FALSE; if ( match->if_data != NULL ) { gchar **data; for ( data = match->if_data ; ( *data != NULL ) && ( ! skip ) ; ++data ) { if ( ! eventd_event_has_data(event, *data) ) skip = TRUE; } if ( skip ) continue; } if ( match->if_data_matches != NULL ) { GList *data_match_; const gchar *data; for ( data_match_ = match->if_data_matches ; ( data_match_ != NULL ) && ( ! skip ) ; data_match_ = g_list_next(data_match_) ) { EventdConfigDataMatch *data_match = data_match_->data; if ( ( data = eventd_event_get_data(event, data_match->data) ) == NULL ) continue; if ( ! g_regex_match(data_match->regex, data, 0, NULL) ) skip = TRUE; } if ( skip ) continue; } if ( current_flags != NULL ) { GQuark *flag; if ( match->flags_whitelist != NULL ) { GQuark *wflag; for ( wflag = match->flags_whitelist ; ( *wflag != 0 ) && ( ! skip ) ; ++wflag ) { for ( flag = current_flags ; ( *flag != 0 ) && ( ! skip ) ; ++flag ) { if ( *flag != *wflag ) skip = TRUE; } } if ( skip ) continue; } if ( match->flags_blacklist != NULL ) { GQuark *bflag; for ( bflag = match->flags_blacklist ; ( *bflag != 0 ) && ( ! skip ) ; ++bflag ) { for ( flag = current_flags ; ( *flag != 0 ) && ( ! skip ) ; ++flag ) { if ( *flag == *bflag ) skip = TRUE; } } if ( skip ) continue; } } return match->id; } return NULL; }
EVENTD_EXPORT FilenameProcessResult evhelpers_filename_process(const Filename *filename, EventdEvent *event, const gchar *subdir, gchar **ret_uri, GVariant **ret_data) { g_return_val_if_fail(filename != NULL, FILENAME_PROCESS_RESULT_NONE); g_return_val_if_fail(event != NULL, FILENAME_PROCESS_RESULT_NONE); g_return_val_if_fail(subdir != NULL, FILENAME_PROCESS_RESULT_NONE); g_return_val_if_fail(ret_uri != NULL, FILENAME_PROCESS_RESULT_NONE); g_return_val_if_fail(ret_data != NULL, FILENAME_PROCESS_RESULT_NONE); gchar *uri = NULL; if ( filename->data_name != NULL ) { GVariant *data; data = eventd_event_get_data(event, filename->data_name); if ( data == NULL ) return FILENAME_PROCESS_RESULT_NONE; if ( g_variant_is_of_type(data, G_VARIANT_TYPE_STRING) ) uri = g_variant_dup_string(data, NULL); else if ( g_variant_is_of_type(data, G_VARIANT_TYPE("(msmsv)")) ) { *ret_data = g_variant_ref(data); return FILENAME_PROCESS_RESULT_DATA; } else return FILENAME_PROCESS_RESULT_NONE; } else if ( filename->file_uri != NULL ) uri = evhelpers_format_string_get_string(filename->file_uri, event, NULL, NULL); else g_return_val_if_reached(FILENAME_PROCESS_RESULT_NONE); if ( uri == NULL ) return FILENAME_PROCESS_RESULT_NONE; if ( *uri == '\0' ) { g_free(uri); return FILENAME_PROCESS_RESULT_NONE; } if ( g_str_has_prefix(uri, "data:") ) { gchar *mime_type = uri + strlen("data:"); if ( _evhelpers_filename_check_data_base64_prefix(mime_type) ) { gchar *c; guchar *data; gsize length; /* We checked for ";base64," already */ c = g_utf8_strchr(mime_type, -1, ','); *c = '\0'; data = g_base64_decode(c + 1, &length); c = g_utf8_strchr(mime_type, c - mime_type, ';'); *c++ = '\0'; if ( *mime_type == '\0' ) mime_type = NULL; if ( *c == '\0' ) c = NULL; *ret_data = g_variant_new("(msmsv)", mime_type, c, g_variant_new_from_data(G_VARIANT_TYPE_BYTESTRING, data, length, FALSE, g_free, data)); g_free(uri); return FILENAME_PROCESS_RESULT_DATA; } } else if ( g_str_has_prefix(uri, "file://") ) { const gchar *p = uri + strlen("file://"); if ( ! g_path_is_absolute(p) ) { gchar *tmp = uri; if ( g_path_is_absolute(subdir) ) uri = g_strconcat("file://", subdir, G_DIR_SEPARATOR_S, p, NULL); else uri = g_strconcat("file://", g_get_user_data_dir(), G_DIR_SEPARATOR_S PACKAGE_NAME G_DIR_SEPARATOR_S, subdir, G_DIR_SEPARATOR_S, p, NULL); g_free(tmp); p = uri + strlen("file://"); } if ( g_file_test(p, G_FILE_TEST_IS_REGULAR) ) { *ret_uri = uri; return FILENAME_PROCESS_RESULT_URI; } } else if ( g_str_has_prefix(uri, "theme:") ) { *ret_uri = uri; return FILENAME_PROCESS_RESULT_THEME; } g_free(uri); return FILENAME_PROCESS_RESULT_NONE; }
static const gchar * _evhelpers_token_list_callback(const gchar *token, guint64 value, gpointer user_data) { FormatStringReplaceData *data = user_data; if ( data->callback != NULL ) return data->callback(token, data->event, data->user_data); g_free(data->to_free); data->to_free = NULL; GVariant *content; content = eventd_event_get_data(data->event, token); if ( content == NULL ) return NULL; if ( g_variant_is_of_type(content, G_VARIANT_TYPE_STRING) ) return g_variant_get_string(content, NULL); if ( g_variant_is_of_type(content, G_VARIANT_TYPE_BOOLEAN) ) return g_variant_get_boolean(content) ? "true" : NULL; #define _evhelpers_check_type_with_format(l, U, GFormat) G_STMT_START { \ if ( g_variant_is_of_type(content, G_VARIANT_TYPE_##U) ) \ { \ g_snprintf(data->number, sizeof(data->number), "%" GFormat, g_variant_get_##l(content)); \ return data->number; \ } \ } G_STMT_END #define _evhelpers_check_type(l, U) _evhelpers_check_type_with_format(l, U, G_G##U##_FORMAT) _evhelpers_check_type(int16, INT16); _evhelpers_check_type(int32, INT32); _evhelpers_check_type(int64, INT64); _evhelpers_check_type_with_format(byte, BYTE, "hhu"); _evhelpers_check_type(uint16, UINT16); _evhelpers_check_type(uint32, UINT32); _evhelpers_check_type(uint64, UINT64); _evhelpers_check_type_with_format(double, DOUBLE, "lf"); #undef _evhelpers_check_type #undef _evhelpers_check_type_with_format if ( g_variant_is_of_type(content, G_VARIANT_TYPE_STRING_ARRAY) ) { const gchar **strv; gsize length; GString *ret; strv = g_variant_get_strv(content, &length); if ( length > 0 ) { ret = g_string_sized_new(length * strlen(strv[0])); for ( ; *strv != NULL ; ++strv ) g_string_append_c(g_string_append(ret, *strv), ' '); g_string_truncate(ret, ret->len - 1); data->to_free = g_string_free(ret, FALSE); } } else data->to_free = g_variant_print(content, FALSE); return data->to_free; }
static gboolean _eventd_events_event_matches(EventdEventsEvent *self, EventdEvent *event, GQuark *current_flags) { if ( self->if_data != NULL ) { gchar **data; for ( data = self->if_data ; *data != NULL ; ++data ) { if ( ! eventd_event_has_data(event, *data) ) return FALSE; } } if ( self->if_data_matches != NULL ) { EventdEventsEventDataMatch *match; GVariant *data; for ( match = self->if_data_matches ; match->data != NULL ; ++match ) { if ( ! eventd_event_has_data(event, match->data) ) continue; if ( ( data = eventd_event_get_data(event, match->data) ) == NULL ) return FALSE; if ( match->key != NULL ) { if ( ! g_variant_is_of_type(data, G_VARIANT_TYPE_VARDICT) ) return FALSE; data = g_variant_lookup_value(data, match->key, g_variant_get_type(match->value)); if ( data == NULL ) return FALSE; } else if ( ! g_variant_type_equal(g_variant_get_type(data), g_variant_get_type(match->value)) ) return FALSE; gint ret; ret = g_variant_compare(data, match->value); ret = CLAMP(ret, -1, 1); if ( ( ret != match->accepted[0] ) && ( ret != match->accepted[1] ) ) return FALSE; } } if ( self->if_data_regexes != NULL ) { EventdEventsEventDataRegex *match; const gchar *data; for ( match = self->if_data_regexes ; match->data != NULL ; ++match ) { if ( ! eventd_event_has_data(event, match->data) ) continue; if ( ( data = eventd_event_get_data_string(event, match->data) ) == NULL ) return FALSE; if ( ! g_regex_match(match->regex, data, 0, NULL) ) return FALSE; } } if ( current_flags != NULL ) { GQuark *flag; if ( self->flags_whitelist != NULL ) { GQuark *wflag; for ( wflag = self->flags_whitelist ; *wflag != 0 ; ++wflag ) { gboolean has = FALSE; for ( flag = current_flags ; ( *flag != 0 ) && ( ! has ) ; ++flag ) { if ( *flag == *wflag ) has = TRUE; } if ( ! has ) return FALSE; } } if ( self->flags_blacklist != NULL ) { GQuark *bflag; for ( bflag = self->flags_blacklist ; *bflag != 0 ; ++bflag ) { for ( flag = current_flags ; *flag != 0 ; ++flag ) { if ( *flag == *bflag ) return FALSE; } } } } return TRUE; }
static void _eventd_nd_notification_process(EventdNdNotification *self, EventdEvent *event) { _eventd_nd_notification_clean(self); if ( event != NULL ) self->event = eventd_event_ref(event); gint border, padding; gint progress_bar_width = 0; gint min_width, max_width; gint text_width = 0, text_max_width; gint image_width = 0, image_height = 0; switch ( self->context->shaping ) { case EVENTD_ND_SHAPING_NONE: case EVENTD_ND_SHAPING_SHAPE: self->offset.x = 0; self->offset.y = 0; self->surface_size.width = 0; self->surface_size.height = 0; break; case EVENTD_ND_SHAPING_COMPOSITING: { gint blur, offset_x, offset_y; blur = eventd_nd_style_get_bubble_border_blur(self->style) * 2; /* We must reserve enough space to avoid clipping */ offset_x = eventd_nd_style_get_bubble_border_blur_offset_x(self->style); offset_y = eventd_nd_style_get_bubble_border_blur_offset_y(self->style); self->offset.x = MAX(0, blur - offset_x); self->offset.y = MAX(0, blur - offset_y); self->surface_size.width = 2 * blur + MAX(0, ABS(offset_x) - blur); self->surface_size.height = 2 * blur + MAX(0, ABS(offset_y) - blur); } break; } border = eventd_nd_style_get_bubble_border(self->style); padding = eventd_nd_style_get_bubble_padding(self->style); min_width = eventd_nd_style_get_bubble_min_width(self->style); max_width = eventd_nd_style_get_bubble_max_width(self->style); switch ( eventd_nd_style_get_progress_placement(self->style) ) { case EVENTD_ND_STYLE_PROGRESS_PLACEMENT_BAR_BOTTOM: if ( self->event != NULL ) { GVariant *val; val = eventd_event_get_data(self->event, eventd_nd_style_get_template_progress(self->style)); if ( val != NULL ) progress_bar_width = eventd_nd_style_get_progress_bar_width(self->style); } break; case EVENTD_ND_STYLE_PROGRESS_PLACEMENT_IMAGE_BOTTOM_TOP: case EVENTD_ND_STYLE_PROGRESS_PLACEMENT_IMAGE_TOP_BOTTOM: case EVENTD_ND_STYLE_PROGRESS_PLACEMENT_IMAGE_LEFT_RIGHT: case EVENTD_ND_STYLE_PROGRESS_PLACEMENT_IMAGE_RIGHT_LEFT: case EVENTD_ND_STYLE_PROGRESS_PLACEMENT_IMAGE_CIRCULAR: break; } if ( max_width < 0 ) max_width = self->context->geometry.w - 2 * ( self->queue->margin_x + border ); max_width -= 2 * padding; min_width += 2 * padding; if ( min_width > max_width ) min_width = max_width; /* proccess data and compute the bubble size */ text_max_width = eventd_nd_style_get_text_max_width(self->style); if ( text_max_width < 0 ) text_max_width = max_width; else text_max_width = MIN(text_max_width, max_width); self->text.text = eventd_nd_draw_text_process(self->style, self->event, text_max_width, g_queue_get_length(self->queue->wait_queue), &text_width); self->content_size.width = text_width; if ( self->content_size.width < max_width ) { if ( self->event != NULL ) eventd_nd_draw_image_and_icon_process(self->context->theme_context, self->style, self->event, max_width - self->content_size.width, self->context->geometry.s, &self->image, &self->icon, &self->text.x, &image_width, &image_height); self->content_size.width += image_width; } /* We are sure that min_width <= max_width */ if ( min_width > self->content_size.width ) { self->content_size.width = min_width; /* Let the text take the remaining space if needed (e.g. Right-to-Left) */ text_width = self->content_size.width - image_width; } pango_layout_set_width(self->text.text, text_width * PANGO_SCALE); pango_layout_get_pixel_size(self->text.text, NULL, &self->text.height); self->content_size.height = MAX(image_height, self->text.height); self->bubble_size.width = self->content_size.width + 2 * padding; self->bubble_size.height = self->content_size.height + 2 * padding + progress_bar_width; self->border_size.width = self->bubble_size.width + 2 * border; self->border_size.height = self->bubble_size.height + 2 * border; self->surface_size.width += self->border_size.width; self->surface_size.height += self->border_size.height; if ( self->timeout > 0 ) { g_source_remove(self->timeout); self->timeout = g_timeout_add_full(G_PRIORITY_DEFAULT, eventd_nd_style_get_bubble_timeout(self->style), _eventd_nd_event_timedout, self, NULL); } }