diff options
Diffstat (limited to 'utils/notify-osd/leolik.patch')
-rw-r--r-- | utils/notify-osd/leolik.patch | 1563 |
1 files changed, 1563 insertions, 0 deletions
diff --git a/utils/notify-osd/leolik.patch b/utils/notify-osd/leolik.patch new file mode 100644 index 0000000000..befb88f877 --- /dev/null +++ b/utils/notify-osd/leolik.patch @@ -0,0 +1,1563 @@ +diff -Naur old_src/bubble.c src/bubble.c +--- old_src/bubble.c 2012-03-23 10:49:59.000000000 -0400 ++++ src/bubble.c 2012-11-10 08:44:21.000000000 -0500 +@@ -119,6 +119,14 @@ + A + }; + ++typedef struct _NotifyHSVColor NotifyHSVColor; ++ ++struct _NotifyHSVColor { ++ gdouble hue; ++ gdouble saturation; ++ gdouble value; ++}; ++ + #define TEMPORARY_ICON_PREFIX_WORKAROUND 1 + #ifdef TEMPORARY_ICON_PREFIX_WORKAROUND + #warning "--== Using the icon-name-substitution! This is a temp. workaround not going to be maintained for long! ==--" +@@ -128,25 +136,25 @@ + // FIXME: this is in class Defaults already, but not yet hooked up so for the + // moment we use the macros here, these values reflect the visual-guideline + // for jaunty notifications +-#define TEXT_TITLE_COLOR_R 1.0f +-#define TEXT_TITLE_COLOR_G 1.0f +-#define TEXT_TITLE_COLOR_B 1.0f +-#define TEXT_TITLE_COLOR_A 1.0f +- +-#define TEXT_BODY_COLOR_R 0.91f +-#define TEXT_BODY_COLOR_G 0.91f +-#define TEXT_BODY_COLOR_B 0.91f +-#define TEXT_BODY_COLOR_A 1.0f ++float TEXT_TITLE_COLOR_R = 1.0f; ++float TEXT_TITLE_COLOR_G = 1.0f; ++float TEXT_TITLE_COLOR_B = 1.0f; ++float TEXT_TITLE_COLOR_A = 1.0f; ++ ++float TEXT_BODY_COLOR_R = 0.91f; ++float TEXT_BODY_COLOR_G = 0.91f; ++float TEXT_BODY_COLOR_B = 0.91f; ++float TEXT_BODY_COLOR_A = 1.0f; + + #define TEXT_SHADOW_COLOR_R 0.0f + #define TEXT_SHADOW_COLOR_G 0.0f + #define TEXT_SHADOW_COLOR_B 0.0f +-#define TEXT_SHADOW_COLOR_A 1.0f ++float TEXT_SHADOW_COLOR_A = 1.0f; + +-#define BUBBLE_BG_COLOR_R 0.15f +-#define BUBBLE_BG_COLOR_G 0.15f +-#define BUBBLE_BG_COLOR_B 0.15f +-#define BUBBLE_BG_COLOR_A 0.9f ++float BUBBLE_BG_COLOR_R = 0.07f; ++float BUBBLE_BG_COLOR_G = 0.07f; ++float BUBBLE_BG_COLOR_B = 0.07f; ++float BUBBLE_BG_COLOR_A = 0.9f; + + #define INDICATOR_UNLIT_R 1.0f + #define INDICATOR_UNLIT_G 1.0f +@@ -167,6 +175,10 @@ + #define BUBBLE_CONTENT_BLUR_RADIUS 4 + #define TEXT_DROP_SHADOW_SIZE 2 + ++gboolean BUBBLE_PREVENT_FADE = TRUE; ++gboolean BUBBLE_CLOSE_ON_CLICK = FALSE; ++gboolean BUBBLE_AS_DESKTOP_BG = FALSE; ++ + //-- private functions --------------------------------------------------------- + + static guint g_bubble_signals[LAST_SIGNAL] = { 0 }; +@@ -487,6 +499,22 @@ + cairo_surface_destroy (new_surface); + } + ++static gdouble ++get_shadow_size (Bubble *bubble) ++{ ++ BubblePrivate* priv = GET_PRIVATE (bubble); ++ Defaults* d = bubble->defaults; ++ return defaults_get_bubble_shadow_size (d, priv->composited); ++} ++ ++static gdouble ++get_corner_radius (Bubble *bubble) ++{ ++ BubblePrivate* priv = GET_PRIVATE (bubble); ++ Defaults* d = bubble->defaults; ++ return defaults_get_bubble_corner_radius (d, priv->composited); ++} ++ + static void + _draw_layout_grid (cairo_t* cr, + Bubble* bubble) +@@ -501,112 +529,112 @@ + + // all vertical grid lines + cairo_move_to (cr, +- 0.5f + EM2PIXELS (defaults_get_bubble_shadow_size (d), d), +- 0.5f + EM2PIXELS (defaults_get_bubble_shadow_size (d), d)); ++ 0.5f + EM2PIXELS (get_shadow_size (bubble), d), ++ 0.5f + EM2PIXELS (get_shadow_size (bubble), d)); + cairo_line_to (cr, +- 0.5f + EM2PIXELS (defaults_get_bubble_shadow_size (d), d), ++ 0.5f + EM2PIXELS (get_shadow_size (bubble), d), + 0.5f + (gdouble) bubble_get_height (bubble) - +- EM2PIXELS (defaults_get_bubble_shadow_size (d), d)); ++ EM2PIXELS (get_shadow_size (bubble), d)); + cairo_move_to (cr, +- 0.5f + EM2PIXELS (defaults_get_bubble_shadow_size (d), d) + ++ 0.5f + EM2PIXELS (get_shadow_size (bubble), d) + + EM2PIXELS (defaults_get_margin_size (d), d), +- 0.5f + EM2PIXELS (defaults_get_bubble_shadow_size (d), d)); ++ 0.5f + EM2PIXELS (get_shadow_size (bubble), d)); + cairo_line_to (cr, +- 0.5f + EM2PIXELS (defaults_get_bubble_shadow_size (d), d) + ++ 0.5f + EM2PIXELS (get_shadow_size (bubble), d) + + EM2PIXELS (defaults_get_margin_size (d), d), + 0.5f + (gdouble) bubble_get_height (bubble) - +- EM2PIXELS (defaults_get_bubble_shadow_size (d), d)); ++ EM2PIXELS (get_shadow_size (bubble), d)); + cairo_move_to (cr, +- 0.5f + EM2PIXELS (defaults_get_bubble_shadow_size (d), d) + ++ 0.5f + EM2PIXELS (get_shadow_size (bubble), d) + + EM2PIXELS (defaults_get_margin_size (d), d) + + EM2PIXELS (defaults_get_icon_size (d), d), +- 0.5f + EM2PIXELS (defaults_get_bubble_shadow_size (d), d)); ++ 0.5f + EM2PIXELS (get_shadow_size (bubble), d)); + cairo_line_to (cr, +- 0.5f + EM2PIXELS (defaults_get_bubble_shadow_size (d), d) + ++ 0.5f + EM2PIXELS (get_shadow_size (bubble), d) + + EM2PIXELS (defaults_get_margin_size (d), d) + + EM2PIXELS (defaults_get_icon_size (d), d), + 0.5f + (gdouble) bubble_get_height (bubble) - +- EM2PIXELS (defaults_get_bubble_shadow_size (d), d)); ++ EM2PIXELS (get_shadow_size (bubble), d)); + cairo_move_to (cr, +- 0.5f + EM2PIXELS (defaults_get_bubble_shadow_size (d), d) + ++ 0.5f + EM2PIXELS (get_shadow_size (bubble), d) + + EM2PIXELS (2 * defaults_get_margin_size (d), d) + + EM2PIXELS (defaults_get_icon_size (d), d), +- 0.5f + EM2PIXELS (defaults_get_bubble_shadow_size (d), d)); ++ 0.5f + EM2PIXELS (get_shadow_size (bubble), d)); + cairo_line_to (cr, +- 0.5f + EM2PIXELS (defaults_get_bubble_shadow_size (d), d) + ++ 0.5f + EM2PIXELS (get_shadow_size (bubble), d) + + EM2PIXELS (2 * defaults_get_margin_size (d), d) + + EM2PIXELS (defaults_get_icon_size (d), d), + 0.5f + (gdouble) bubble_get_height (bubble) - +- EM2PIXELS (defaults_get_bubble_shadow_size (d), d)); ++ EM2PIXELS (get_shadow_size (bubble), d)); + cairo_move_to (cr, +- 0.5f + EM2PIXELS (defaults_get_bubble_shadow_size (d), d) + ++ 0.5f + EM2PIXELS (get_shadow_size (bubble), d) + + EM2PIXELS (defaults_get_bubble_width (d), d) - + EM2PIXELS (defaults_get_margin_size (d), d), +- 0.5f + EM2PIXELS (defaults_get_bubble_shadow_size (d), d)); ++ 0.5f + EM2PIXELS (get_shadow_size (bubble), d)); + cairo_line_to (cr, +- 0.5f + EM2PIXELS (defaults_get_bubble_shadow_size (d), d) + ++ 0.5f + EM2PIXELS (get_shadow_size (bubble), d) + + EM2PIXELS (defaults_get_bubble_width (d), d) - + EM2PIXELS (defaults_get_margin_size (d), d), + 0.5f + (gdouble) bubble_get_height (bubble) - +- EM2PIXELS (defaults_get_bubble_shadow_size (d), d)); ++ EM2PIXELS (get_shadow_size (bubble), d)); + cairo_move_to (cr, +- 0.5f + EM2PIXELS (defaults_get_bubble_shadow_size (d), d) + ++ 0.5f + EM2PIXELS (get_shadow_size (bubble), d) + + EM2PIXELS (defaults_get_bubble_width (d), d), +- 0.5f + EM2PIXELS (defaults_get_bubble_shadow_size (d), d)); ++ 0.5f + EM2PIXELS (get_shadow_size (bubble), d)); + cairo_line_to (cr, +- 0.5f + EM2PIXELS (defaults_get_bubble_shadow_size (d), d) + ++ 0.5f + EM2PIXELS (get_shadow_size (bubble), d) + + EM2PIXELS (defaults_get_bubble_width (d), d), + 0.5f + (gdouble) bubble_get_height (bubble) - +- EM2PIXELS (defaults_get_bubble_shadow_size (d), d)); ++ EM2PIXELS (get_shadow_size (bubble), d)); + + // all horizontal grid lines + cairo_move_to (cr, +- 0.5f + EM2PIXELS (defaults_get_bubble_shadow_size (d), d), +- 0.5f + EM2PIXELS (defaults_get_bubble_shadow_size (d), d)); ++ 0.5f + EM2PIXELS (get_shadow_size (bubble), d), ++ 0.5f + EM2PIXELS (get_shadow_size (bubble), d)); + cairo_line_to (cr, +- 0.5f + EM2PIXELS (defaults_get_bubble_shadow_size (d), d) + ++ 0.5f + EM2PIXELS (get_shadow_size (bubble), d) + + EM2PIXELS (defaults_get_bubble_width (d), d), +- 0.5f + EM2PIXELS (defaults_get_bubble_shadow_size (d), d)); ++ 0.5f + EM2PIXELS (get_shadow_size (bubble), d)); + cairo_move_to (cr, +- 0.5f + EM2PIXELS (defaults_get_bubble_shadow_size (d), d), +- 0.5f + EM2PIXELS (defaults_get_bubble_shadow_size (d), d) + ++ 0.5f + EM2PIXELS (get_shadow_size (bubble), d), ++ 0.5f + EM2PIXELS (get_shadow_size (bubble), d) + + EM2PIXELS (defaults_get_margin_size (d), d)); + cairo_line_to (cr, +- 0.5f + EM2PIXELS (defaults_get_bubble_shadow_size (d), d) + ++ 0.5f + EM2PIXELS (get_shadow_size (bubble), d) + + EM2PIXELS (defaults_get_bubble_width (d), d), +- 0.5f + EM2PIXELS (defaults_get_bubble_shadow_size (d), d) + ++ 0.5f + EM2PIXELS (get_shadow_size (bubble), d) + + EM2PIXELS (defaults_get_margin_size (d), d)); + cairo_move_to (cr, +- 0.5f + EM2PIXELS (defaults_get_bubble_shadow_size (d), d), +- 0.5f + EM2PIXELS (defaults_get_bubble_shadow_size (d), d) + ++ 0.5f + EM2PIXELS (get_shadow_size (bubble), d), ++ 0.5f + EM2PIXELS (get_shadow_size (bubble), d) + + EM2PIXELS (defaults_get_margin_size (d), d) + + EM2PIXELS (defaults_get_icon_size (d), d)); + cairo_line_to (cr, +- 0.5f + EM2PIXELS (defaults_get_bubble_shadow_size (d), d) + ++ 0.5f + EM2PIXELS (get_shadow_size (bubble), d) + + EM2PIXELS (defaults_get_bubble_width (d), d), +- 0.5f + EM2PIXELS (defaults_get_bubble_shadow_size (d), d) + ++ 0.5f + EM2PIXELS (get_shadow_size (bubble), d) + + EM2PIXELS (defaults_get_margin_size (d), d) + + EM2PIXELS (defaults_get_icon_size (d), d)); + cairo_move_to (cr, +- 0.5f + EM2PIXELS (defaults_get_bubble_shadow_size (d), d), ++ 0.5f + EM2PIXELS (get_shadow_size (bubble), d), + 0.5f + (gdouble) bubble_get_height (bubble) - +- EM2PIXELS (defaults_get_bubble_shadow_size (d), d) - ++ EM2PIXELS (get_shadow_size (bubble), d) - + EM2PIXELS (defaults_get_margin_size (d), d)); + cairo_line_to (cr, +- 0.5f + EM2PIXELS (defaults_get_bubble_shadow_size (d), d) + ++ 0.5f + EM2PIXELS (get_shadow_size (bubble), d) + + EM2PIXELS (defaults_get_bubble_width (d), d), + 0.5f + (gdouble) bubble_get_height (bubble) - +- EM2PIXELS (defaults_get_bubble_shadow_size (d), d) - ++ EM2PIXELS (get_shadow_size (bubble), d) - + EM2PIXELS (defaults_get_margin_size (d), d)); + cairo_move_to (cr, +- 0.5f + EM2PIXELS (defaults_get_bubble_shadow_size (d), d), ++ 0.5f + EM2PIXELS (get_shadow_size (bubble), d), + 0.5f + (gdouble) bubble_get_height (bubble) - +- EM2PIXELS (defaults_get_bubble_shadow_size (d), d)); ++ EM2PIXELS (get_shadow_size (bubble), d)); + cairo_line_to (cr, +- 0.5f + EM2PIXELS (defaults_get_bubble_shadow_size (d), d) + ++ 0.5f + EM2PIXELS (get_shadow_size (bubble), d) + + EM2PIXELS (defaults_get_bubble_width (d), d), + 0.5f + (gdouble) bubble_get_height (bubble) - +- EM2PIXELS (defaults_get_bubble_shadow_size (d), d)); ++ EM2PIXELS (get_shadow_size (bubble), d)); + + cairo_stroke (cr); + } +@@ -625,20 +653,28 @@ + raico_blur_t* blur = NULL; + gint width; + gint height; ++ gint scratch_shadow_size; + + bubble_get_size (self, &width, &height); + + // create temp. scratch surface for top-left shadow/background part + if (priv->composited) ++ { ++ scratch_shadow_size = EM2PIXELS (get_shadow_size (self), d); + scratch = cairo_image_surface_create ( + CAIRO_FORMAT_ARGB32, +- 3 * EM2PIXELS (defaults_get_bubble_shadow_size (d), d), +- 3 * EM2PIXELS (defaults_get_bubble_shadow_size (d), d)); ++ 3 * scratch_shadow_size, ++ 3 * scratch_shadow_size); ++ } + else ++ { ++ // We must have at least some width to this scratch surface. ++ scratch_shadow_size = 1; + scratch = cairo_image_surface_create ( + CAIRO_FORMAT_RGB24, +- 3 * EM2PIXELS (defaults_get_bubble_shadow_size (d), d), +- 3 * EM2PIXELS (defaults_get_bubble_shadow_size (d), d)); ++ 3 * scratch_shadow_size, ++ 3 * scratch_shadow_size); ++ } + + g_return_if_fail (scratch); + +@@ -673,48 +709,72 @@ + color_string = defaults_get_bubble_bg_color (d); + gdk_rgba_parse (&color, color_string); + g_free (color_string); +- ++ ++ // Apply color tweaks ++ NotifyHSVColor hsv_color; ++ gtk_rgb_to_hsv (color.red, color.green, color.blue, ++ &hsv_color.hue, &hsv_color.saturation, &hsv_color.value); ++ hsv_color.saturation *= (2.0f - hsv_color.saturation); ++ hsv_color.value = MIN (hsv_color.value, 0.4f); ++ gtk_hsv_to_rgb (hsv_color.hue, hsv_color.saturation, hsv_color.value, ++ &color.red, &color.green, &color.blue); ++ + if (priv->composited) + { + _draw_shadow ( + cr, + width, + height, +- EM2PIXELS (defaults_get_bubble_shadow_size (d), d), +- EM2PIXELS (defaults_get_bubble_corner_radius (d), d)); ++ EM2PIXELS (get_shadow_size (self), d), ++ EM2PIXELS (get_corner_radius (self), d)); + cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR); + draw_round_rect ( + cr, + 1.0f, +- EM2PIXELS (defaults_get_bubble_shadow_size (d), d), +- EM2PIXELS (defaults_get_bubble_shadow_size (d), d), +- EM2PIXELS (defaults_get_bubble_corner_radius (d), d), ++ EM2PIXELS (get_shadow_size (self), d), ++ EM2PIXELS (get_shadow_size (self), d), ++ EM2PIXELS (get_corner_radius (self), d), + EM2PIXELS (defaults_get_bubble_width (d), d), + (gdouble) bubble_get_height (self) - +- 2.0f * EM2PIXELS (defaults_get_bubble_shadow_size (d), d)); ++ 2.0f * EM2PIXELS (get_shadow_size (self), d)); + cairo_fill (cr); + cairo_set_operator (cr, CAIRO_OPERATOR_OVER); +- cairo_set_source_rgba (cr, +- 0.75 * color.red, +- 0.75 * color.green, +- 0.75 * color.blue, +- BUBBLE_BG_COLOR_A); ++ if (BUBBLE_AS_DESKTOP_BG) { ++ cairo_set_source_rgba (cr, ++ color.red, ++ color.green, ++ color.blue, ++ BUBBLE_BG_COLOR_A); ++ } else { ++ cairo_set_source_rgba (cr, ++ BUBBLE_BG_COLOR_R, ++ BUBBLE_BG_COLOR_G, ++ BUBBLE_BG_COLOR_B, ++ BUBBLE_BG_COLOR_A); ++ } + } + else +- cairo_set_source_rgb (cr, +- 0.75 * color.red, +- 0.75 * color.green, +- 0.75 * color.blue); ++ if (BUBBLE_AS_DESKTOP_BG) { ++ cairo_set_source_rgb (cr, ++ color.red, ++ color.green, ++ color.blue); ++ } else { ++ cairo_set_source_rgb (cr, ++ BUBBLE_BG_COLOR_R, ++ BUBBLE_BG_COLOR_G, ++ BUBBLE_BG_COLOR_B); ++ } + + draw_round_rect ( + cr, + 1.0f, +- EM2PIXELS (defaults_get_bubble_shadow_size (d), d), +- EM2PIXELS (defaults_get_bubble_shadow_size (d), d), +- EM2PIXELS (defaults_get_bubble_corner_radius (d), d), ++ EM2PIXELS (get_shadow_size (self), d), ++ EM2PIXELS (get_shadow_size (self), d), ++ EM2PIXELS (get_corner_radius (self), d), + EM2PIXELS (defaults_get_bubble_width (d), d), + (gdouble) bubble_get_height (self) - +- 2.0f * EM2PIXELS (defaults_get_bubble_shadow_size (d), d)); ++ 2.0f * EM2PIXELS (get_shadow_size (self), d)); + cairo_fill (cr); + cairo_destroy (cr); + +@@ -722,8 +782,8 @@ + dummy = cairo_image_surface_create_for_data ( + cairo_image_surface_get_data (scratch), + cairo_image_surface_get_format (scratch), +- 3 * EM2PIXELS (defaults_get_bubble_shadow_size (d), d), +- 3 * EM2PIXELS (defaults_get_bubble_shadow_size (d), d), ++ 3 * scratch_shadow_size, ++ 3 * scratch_shadow_size, + cairo_image_surface_get_stride (scratch)); + clone = copy_surface (dummy); + cairo_surface_destroy (dummy); +@@ -732,8 +792,8 @@ + dummy = cairo_image_surface_create_for_data ( + cairo_image_surface_get_data (clone), + cairo_image_surface_get_format (clone), +- 2 * EM2PIXELS (defaults_get_bubble_shadow_size (d), d), +- 2 * EM2PIXELS (defaults_get_bubble_shadow_size (d), d), ++ 2 * scratch_shadow_size, ++ 2 * scratch_shadow_size, + cairo_image_surface_get_stride (clone)); + normal = copy_surface (dummy); + cairo_surface_destroy (dummy); +@@ -748,8 +808,8 @@ + dummy = cairo_image_surface_create_for_data ( + cairo_image_surface_get_data (clone), + cairo_image_surface_get_format (clone), +- 2 * EM2PIXELS (defaults_get_bubble_shadow_size (d), d), +- 2 * EM2PIXELS (defaults_get_bubble_shadow_size (d), d), ++ 2 * scratch_shadow_size, ++ 2 * scratch_shadow_size, + cairo_image_surface_get_stride (clone)); + blurred = copy_surface (dummy); + cairo_surface_destroy (dummy); +@@ -1265,11 +1325,11 @@ + draw_round_rect ( + cr, + 1.0f, +- EM2PIXELS (defaults_get_bubble_shadow_size (d), d) + 2.0f, +- EM2PIXELS (defaults_get_bubble_shadow_size (d), d) + 2.0f, +- EM2PIXELS (defaults_get_bubble_corner_radius (d), d) - 2.0f, ++ EM2PIXELS (get_shadow_size (self), d) + 2.0f, ++ EM2PIXELS (get_shadow_size (self), d) + 2.0f, ++ EM2PIXELS (get_corner_radius (self), d) - 2.0f, + EM2PIXELS (defaults_get_bubble_width (d), d) - 4.0f, +- 2.0f * EM2PIXELS (defaults_get_bubble_shadow_size (d), d) - 2.0f); ++ 2.0f * EM2PIXELS (get_shadow_size (self), d) - 2.0f); + cairo_fill (cr); + + cairo_set_source_rgb (cr, 0.0f, 0.0f, 0.0f); +@@ -1279,12 +1339,12 @@ + cairo_move_to ( + cr, + EM2PIXELS (defaults_get_text_body_size (d), d) + +- EM2PIXELS (defaults_get_bubble_shadow_size (d), d) + ++ EM2PIXELS (get_shadow_size (self), d) + + 2.0f, + EM2PIXELS (defaults_get_text_body_size (d), d) + +- EM2PIXELS (defaults_get_bubble_shadow_size (d), d) + ++ EM2PIXELS (get_shadow_size (self), d) + + 2.0f + +- ((2.0f * EM2PIXELS (defaults_get_bubble_shadow_size (d), d) - 2.0f) - ++ ((2.0f * EM2PIXELS (get_shadow_size (self), d) - 2.0f) - + EM2PIXELS (defaults_get_text_body_size (d), d)) / 2); + + switch (bubble_get_urgency (self)) +@@ -1428,7 +1488,7 @@ + gdouble alpha_blur) + { + Defaults* d = self->defaults; +- gint shadow = EM2PIXELS (defaults_get_bubble_shadow_size (d), d); ++ gint shadow = EM2PIXELS (get_shadow_size (self), d); + gint icon_half = EM2PIXELS (defaults_get_icon_size (d), d) / 2; + gint width_half = EM2PIXELS (defaults_get_bubble_width (d), d) / 2; + gint height_half = EM2PIXELS (defaults_get_bubble_min_height (d), d) / 2; +@@ -1605,15 +1665,23 @@ + // sanity check + if (!window) + return; +- +- // set an 1x1 input-region to allow click-through +- region = cairo_region_create_rectangle (&rect); +- if (cairo_region_status (region) == CAIRO_STATUS_SUCCESS) ++ ++ if (!BUBBLE_CLOSE_ON_CLICK) + { +- gtk_widget_input_shape_combine_region (window, NULL); +- gtk_widget_input_shape_combine_region (window, region); ++ // set an 1x1 input-region to allow click-through ++ region = cairo_region_create_rectangle (&rect); ++ if (cairo_region_status (region) == CAIRO_STATUS_SUCCESS) ++ { ++ gtk_widget_input_shape_combine_region (window, NULL); ++ gtk_widget_input_shape_combine_region (window, region); ++ } ++ cairo_region_destroy (region); ++ } ++ else ++ { ++ GdkWindow *window_ = gtk_widget_get_window (window); ++ gdk_window_set_events (window_, gdk_window_get_events (window_) | GDK_BUTTON_PRESS); + } +- cairo_region_destroy (region); + } + + static void +@@ -1703,7 +1771,7 @@ + cairo_paint (cr); + cairo_set_operator (cr, CAIRO_OPERATOR_OVER); + +- if (priv->prevent_fade || !priv->composited) ++ if (!BUBBLE_PREVENT_FADE || priv->prevent_fade || !priv->composited) + { + // render drop-shadow and bubble-background + _render_background (bubble, cr, 1.0f, 0.0f); +@@ -1730,12 +1798,35 @@ + + _set_bg_blur (window, + TRUE, +- EM2PIXELS (defaults_get_bubble_shadow_size (d), d)); ++ EM2PIXELS (get_shadow_size (bubble), d)); + + return TRUE; + } + + static gboolean ++button_press_event_handler (GtkWidget* window G_GNUC_UNUSED, ++ GdkEventButton* event, ++ Bubble* bubble) ++{ ++ BubblePrivate *priv = GET_PRIVATE (bubble); ++ ++ if (priv->mouse_over && event->button == 1) ++ { ++ bubble_hide (bubble); ++ ++ dbus_send_close_signal (bubble_get_sender (bubble), ++ bubble_get_id (bubble), ++ 1); ++ ++ g_signal_emit (bubble, g_bubble_signals[TIMED_OUT], 0); ++ ++ return TRUE; ++ } ++ ++ return FALSE; ++} ++ ++static gboolean + redraw_handler (Bubble* bubble) + { + GtkWindow* window; +@@ -1759,7 +1850,7 @@ + + if (priv->alpha == NULL) + { +- if (priv->distance < 1.0f && !priv->prevent_fade) ++ if (priv->distance < 1.0f && !priv->prevent_fade && BUBBLE_PREVENT_FADE) + { + gtk_window_set_opacity (window, + WINDOW_MIN_OPACITY + +@@ -1914,7 +2005,7 @@ + + // mark mouse-pointer having left bubble and proximity-area + // after inital show-up of bubble +- if (priv->prevent_fade && priv->distance > 1.0f) ++ if (BUBBLE_PREVENT_FADE && priv->prevent_fade && priv->distance > 1.0f) + priv->prevent_fade = FALSE; + } + +@@ -2210,6 +2301,14 @@ + G_CALLBACK (expose_handler), + this); + ++ if (BUBBLE_CLOSE_ON_CLICK) ++ { ++ g_signal_connect (window, ++ "button-press-event", ++ G_CALLBACK (button_press_event_handler), ++ this); ++ } ++ + // "clear" input-mask, set title/icon/attributes + gtk_widget_set_app_paintable (window, TRUE); + gtk_window_set_title (GTK_WINDOW (window), "notify-osd"); +@@ -2689,7 +2788,7 @@ + + priv = GET_PRIVATE (self); + +- if (priv->prevent_fade) ++ if (BUBBLE_PREVENT_FADE && priv->prevent_fade) + return FALSE; + + return priv->mouse_over; +@@ -2793,7 +2892,7 @@ + + // check if mouse-pointer is over bubble (and proximity-area) initially + pointer_update (self); +- if (priv->distance <= 1.0f) ++ if (priv->distance <= 1.0f || !BUBBLE_PREVENT_FADE) + priv->prevent_fade = TRUE; + else + priv->prevent_fade = FALSE; +@@ -3351,6 +3450,8 @@ + gint old_bubble_height = 0; + gint new_bubble_width = 0; + gint new_bubble_height = 0; ++ gint x; ++ gint y; + Defaults* d; + BubblePrivate* priv; + +@@ -3379,7 +3480,7 @@ + + new_bubble_width = + EM2PIXELS (defaults_get_bubble_width (d), d) + +- 2 * EM2PIXELS (defaults_get_bubble_shadow_size (d), d); ++ 2 * EM2PIXELS (get_shadow_size (self), d); + + switch (priv->layout) + { +@@ -3397,7 +3498,7 @@ + + new_bubble_height = + EM2PIXELS (defaults_get_bubble_min_height (d), d) + +- 2.0f * EM2PIXELS (defaults_get_bubble_shadow_size (d), d); ++ 2.0f * EM2PIXELS (get_shadow_size (self), d); + break; + + case LAYOUT_ICON_TITLE_BODY: +@@ -3446,7 +3547,7 @@ + new_bubble_height = + EM2PIXELS (defaults_get_icon_size (d), d) + + 2.0f * EM2PIXELS (defaults_get_margin_size (d), d) + +- 2.0f * EM2PIXELS (defaults_get_bubble_shadow_size (d), d); ++ 2.0f * EM2PIXELS (get_shadow_size (self), d); + } + else + { +@@ -3454,7 +3555,7 @@ + priv->body_height + + priv->title_height + + 2.0f * EM2PIXELS (defaults_get_margin_size (d), d) + +- 2.0f * EM2PIXELS (defaults_get_bubble_shadow_size (d), d); ++ 2.0f * EM2PIXELS (get_shadow_size (self), d); + } + } + } +@@ -3501,7 +3602,7 @@ + priv->body_height + + priv->title_height + + 2.0f * EM2PIXELS (defaults_get_margin_size (d), d) + +- 2.0f * EM2PIXELS (defaults_get_bubble_shadow_size (d), d); ++ 2.0f * EM2PIXELS (get_shadow_size (self), d); + } + } + break; +@@ -3518,7 +3619,7 @@ + + new_bubble_height = priv->title_height + + 2.0f * EM2PIXELS (defaults_get_margin_size (d), d) + +- 2.0f * EM2PIXELS (defaults_get_bubble_shadow_size (d), d); ++ 2.0f * EM2PIXELS (get_shadow_size (self), d); + } + break; + +@@ -3545,6 +3646,13 @@ + _refresh_body (self); + + update_shape (self); ++ ++ if (defaults_get_gravity (d) == GRAVITY_SOUTH_EAST) ++ { ++ bubble_get_position(self, &x, &y); ++ bubble_move(self, x, y - (new_bubble_height - old_bubble_height)); ++ } ++ + } + + void +diff -Naur old_src/defaults.c src/defaults.c +--- old_src/defaults.c 2012-03-23 10:49:59.000000000 -0400 ++++ src/defaults.c 2012-11-10 08:44:21.000000000 -0500 +@@ -110,40 +110,41 @@ + /* these values are interpreted as em-measurements and do comply to the + * visual guide for jaunty-notifications */ + #define DEFAULT_DESKTOP_BOTTOM_GAP 6.0f +-#define DEFAULT_BUBBLE_WIDTH 24.0f +-#define DEFAULT_BUBBLE_MIN_HEIGHT 5.0f +-#define DEFAULT_BUBBLE_MAX_HEIGHT 12.2f +-#define DEFAULT_BUBBLE_VERT_GAP 0.5f +-#define DEFAULT_BUBBLE_HORZ_GAP 0.5f ++float DEFAULT_BUBBLE_WIDTH = 24.0f; ++float DEFAULT_BUBBLE_MIN_HEIGHT = 5.0f; ++float DEFAULT_BUBBLE_MAX_HEIGHT = 12.2f; ++float DEFAULT_BUBBLE_VERT_GAP = 0.5f; ++float DEFAULT_BUBBLE_HORZ_GAP = 0.5f; + #define DEFAULT_BUBBLE_SHADOW_SIZE 0.7f + #define DEFAULT_BUBBLE_SHADOW_COLOR "#000000" + #define DEFAULT_BUBBLE_BG_COLOR "#131313" + #define DEFAULT_BUBBLE_BG_OPACITY "#cc" + #define DEFAULT_BUBBLE_HOVER_OPACITY "#66" +-#define DEFAULT_BUBBLE_CORNER_RADIUS 0.375f ++float DEFAULT_BUBBLE_CORNER_RADIUS = 0.375f; + #define DEFAULT_CONTENT_SHADOW_SIZE 0.125f + #define DEFAULT_CONTENT_SHADOW_COLOR "#000000" +-#define DEFAULT_MARGIN_SIZE 1.0f +-#define DEFAULT_ICON_SIZE 3.0f +-#define DEFAULT_GAUGE_SIZE 0.625f +-#define DEFAULT_GAUGE_OUTLINE_WIDTH 0.125f ++float DEFAULT_MARGIN_SIZE = 1.0f; ++float DEFAULT_ICON_SIZE = 3.0f; ++float DEFAULT_GAUGE_SIZE = 0.625f; ++#define DEFAULT_GAUGE_OUTLINE_WIDTH 0.125f + #define DEFAULT_TEXT_FONT_FACE "Sans" + #define DEFAULT_TEXT_TITLE_COLOR "#ffffff" +-#define DEFAULT_TEXT_TITLE_WEIGHT TEXT_WEIGHT_BOLD +-#define DEFAULT_TEXT_TITLE_SIZE 1.0f ++short DEFAULT_TEXT_TITLE_WEIGHT = TEXT_WEIGHT_BOLD; ++float DEFAULT_TEXT_TITLE_SIZE = 1.0f; + #define DEFAULT_TEXT_BODY_COLOR "#eaeaea" +-#define DEFAULT_TEXT_BODY_WEIGHT TEXT_WEIGHT_NORMAL +-#define DEFAULT_TEXT_BODY_SIZE 0.9f ++short DEFAULT_TEXT_BODY_WEIGHT = TEXT_WEIGHT_NORMAL; ++float DEFAULT_TEXT_BODY_SIZE = 0.9f; + #define DEFAULT_PIXELS_PER_EM 10.0f + #define DEFAULT_SYSTEM_FONT_SIZE 10.0f + #define DEFAULT_SCREEN_DPI 96.0f + #define DEFAULT_GRAVITY GRAVITY_NORTH_EAST ++short SLOT_ALLOCATION = SLOT_ALLOCATION_DYNAMIC; + + /* these values are interpreted as milliseconds-measurements and do comply to + * the visual guide for jaunty-notifications */ +-#define DEFAULT_FADE_IN_TIMEOUT 250 +-#define DEFAULT_FADE_OUT_TIMEOUT 1000 +-#define DEFAULT_ON_SCREEN_TIMEOUT 10000 ++float DEFAULT_FADE_IN_TIMEOUT = 250; ++float DEFAULT_FADE_OUT_TIMEOUT = 1000; ++float DEFAULT_ON_SCREEN_TIMEOUT = 10000; + + /* notify-osd settings */ + #define NOTIFY_OSD_SCHEMA "com.canonical.notify-osd" +@@ -242,7 +243,7 @@ + gravity = g_settings_get_int (self->nosd_settings, GSETTINGS_GRAVITY_KEY); + + // protect against out-of-bounds values for gravity +- if (gravity != GRAVITY_EAST && gravity != GRAVITY_NORTH_EAST) ++ if (gravity != GRAVITY_EAST && gravity != GRAVITY_NORTH_EAST && gravity != GRAVITY_WEST && gravity != GRAVITY_NORTH_WEST && gravity != GRAVITY_SOUTH_EAST && gravity != GRAVITY_SOUTH_WEST) + gravity = DEFAULT_GRAVITY; + + // update stored DPI-value +@@ -546,7 +547,7 @@ + self); + + // use fixed slot-allocation for async. and sync. bubbles +- self->slot_allocation = SLOT_ALLOCATION_FIXED; ++ self->slot_allocation = SLOT_ALLOCATION; + } + + static void +@@ -1546,7 +1547,7 @@ + "gravity", + "Positional hint for placing bubbles", + 0, +- 2, ++ 6, + DEFAULT_GRAVITY, + G_PARAM_CONSTRUCT | + G_PARAM_READWRITE | +@@ -1762,11 +1763,11 @@ + } + + gdouble +-defaults_get_bubble_shadow_size (Defaults* self) ++defaults_get_bubble_shadow_size (Defaults* self, gboolean is_composited) + { + gdouble bubble_shadow_size; + +- if (!self || !IS_DEFAULTS (self)) ++ if (!self || !IS_DEFAULTS (self) || !is_composited) + return 0.0f; + + g_object_get (self, "bubble-shadow-size", &bubble_shadow_size, NULL); +@@ -1841,11 +1842,11 @@ + } + + gdouble +-defaults_get_bubble_corner_radius (Defaults* self) ++defaults_get_bubble_corner_radius (Defaults* self, gboolean is_composited) + { + gdouble bubble_corner_radius; + +- if (!self || !IS_DEFAULTS (self)) ++ if (!self || !IS_DEFAULTS (self) || !is_composited) + return 0.0f; + + g_object_get (self, +@@ -2205,11 +2206,10 @@ + } + + void +-defaults_get_top_corner (Defaults *self, gint *x, gint *y) ++defaults_get_top_corner (Defaults *self, GdkScreen **screen, gint *x, gint *y) + { + GdkRectangle rect; + GdkRectangle panel_rect = {0, 0, 0, 0}; +- GdkScreen* screen = NULL; + GdkWindow* active_window = NULL; + GdkWindow* panel_window = NULL; + gint mx; +@@ -2219,21 +2219,23 @@ + gint aw_monitor; + gboolean has_panel_window = FALSE; + gboolean follow_focus = defaults_multihead_does_focus_follow (self); ++ gboolean is_composited = FALSE; + + g_return_if_fail (self != NULL && IS_DEFAULTS (self)); + + gdk_display_get_pointer (gdk_display_get_default (), +- &screen, ++ screen, + &mx, + &my, + NULL); + ++ is_composited = gdk_screen_is_composited (*screen); + panel_window = get_panel_window (); + + if (panel_window != NULL) + { + gdk_window_get_frame_extents (panel_window, &panel_rect); +- panel_monitor = gdk_screen_get_monitor_at_window (screen, ++ panel_monitor = gdk_screen_get_monitor_at_window (*screen, + panel_window); + monitor = panel_monitor; + g_debug ("found panel (%d,%d) - %dx%d on monitor %d", +@@ -2249,12 +2251,12 @@ + if (follow_focus) + { + g_debug ("multi_head_focus_follow mode"); +- monitor = gdk_screen_get_monitor_at_point (screen, mx, my); +- active_window = gdk_screen_get_active_window (screen); ++ monitor = gdk_screen_get_monitor_at_point (*screen, mx, my); ++ active_window = gdk_screen_get_active_window (*screen); + if (active_window != NULL) + { + aw_monitor = gdk_screen_get_monitor_at_window ( +- screen, ++ *screen, + active_window); + + if (monitor != aw_monitor) +@@ -2270,7 +2272,7 @@ + } + } + +- gdk_screen_get_monitor_geometry (screen, monitor, &rect); ++ gdk_screen_get_monitor_geometry (*screen, monitor, &rect); + g_debug ("selecting monitor %d at (%d,%d) - %dx%d", + monitor, + rect.x, +@@ -2299,7 +2301,7 @@ + + *y = rect.y; + *y += EM2PIXELS (defaults_get_bubble_vert_gap (self), self) +- - EM2PIXELS (defaults_get_bubble_shadow_size (self), self); ++ - EM2PIXELS (defaults_get_bubble_shadow_size (self, is_composited), self); + + /* correct potential offset in multi-monitor setups with two (or more) + * monitors side by side, all having different vertical resolutions and +@@ -2307,9 +2309,9 @@ + * the top edge of the monitor with the lowest vertical resolution, + * LP: #716458 */ + GdkRectangle cur_geo = {0, 0, 0, 0}; +- int num_monitors = gdk_screen_get_n_monitors (screen); +- int screen_width = gdk_screen_get_width (screen); +- int screen_height = gdk_screen_get_height (screen); ++ int num_monitors = gdk_screen_get_n_monitors (*screen); ++ int screen_width = gdk_screen_get_width (*screen); ++ int screen_height = gdk_screen_get_height (*screen); + + if (!follow_focus && num_monitors > 1) + { +@@ -2319,10 +2321,10 @@ + { + int right_most_monitor = 0; + +- right_most_monitor = gdk_screen_get_monitor_at_point (screen, ++ right_most_monitor = gdk_screen_get_monitor_at_point (*screen, + screen_width, + screen_height / 2); +- gdk_screen_get_monitor_geometry (screen, ++ gdk_screen_get_monitor_geometry (*screen, + right_most_monitor, + &cur_geo); + if (cur_geo.y != 0) +@@ -2332,10 +2334,10 @@ + { + int left_most_monitor = 0; + +- left_most_monitor = gdk_screen_get_monitor_at_point (screen, ++ left_most_monitor = gdk_screen_get_monitor_at_point (*screen, + 0, + screen_height / 2); +- gdk_screen_get_monitor_geometry (screen, ++ gdk_screen_get_monitor_geometry (*screen, + left_most_monitor, + &cur_geo); + if (cur_geo.y != 0) +@@ -2348,12 +2350,12 @@ + if (gtk_widget_get_default_direction () == GTK_TEXT_DIR_LTR) + { + *x = rect.x + rect.width; +- *x -= EM2PIXELS (defaults_get_bubble_shadow_size (self), self) ++ *x -= EM2PIXELS (defaults_get_bubble_shadow_size (self, is_composited), self) + + EM2PIXELS (defaults_get_bubble_horz_gap (self), self) + + EM2PIXELS (defaults_get_bubble_width (self), self); + } else { + *x = rect.x +- - EM2PIXELS (defaults_get_bubble_shadow_size (self), self) ++ - EM2PIXELS (defaults_get_bubble_shadow_size (self, is_composited), self) + + EM2PIXELS (defaults_get_bubble_horz_gap (self), self); + } + +diff -Naur old_src/defaults.h src/defaults.h +--- old_src/defaults.h 2012-03-23 10:49:59.000000000 -0400 ++++ src/defaults.h 2012-11-10 08:44:21.000000000 -0500 +@@ -31,6 +31,7 @@ + + #include <glib-object.h> + #include <gio/gio.h> ++#include <gdk/gdk.h> + + G_BEGIN_DECLS + +@@ -58,7 +59,13 @@ + { + GRAVITY_NONE = 0, + GRAVITY_NORTH_EAST, // top-right of screen +- GRAVITY_EAST // vertically centered at right of screen ++ GRAVITY_EAST, // vertically centered at right of screen ++ GRAVITY_SOUTH_EAST, // bottom-right of screen ++ GRAVITY_SOUTH_WEST, // bottom-left of screen ++ GRAVITY_WEST, // vertically centered at left of screen ++ GRAVITY_NORTH_WEST // top-left of screen ++ ++ + } Gravity; + + typedef enum +@@ -177,7 +184,7 @@ + defaults_get_bubble_horz_gap (Defaults* self); + + gdouble +-defaults_get_bubble_shadow_size (Defaults* self); ++defaults_get_bubble_shadow_size (Defaults* self, gboolean is_composited); + + gchar* + defaults_get_bubble_shadow_color (Defaults* self); +@@ -192,7 +199,7 @@ + defaults_get_bubble_hover_opacity (Defaults* self); + + gdouble +-defaults_get_bubble_corner_radius (Defaults* self); ++defaults_get_bubble_corner_radius (Defaults* self, gboolean is_composited); + + gdouble + defaults_get_content_shadow_size (Defaults* self); +@@ -258,7 +265,7 @@ + defaults_refresh_screen_dimension_properties (Defaults *self); + + void +-defaults_get_top_corner (Defaults *self, gint *x, gint *y); ++defaults_get_top_corner (Defaults *self, GdkScreen **screen, gint *x, gint *y); + + Gravity + defaults_get_gravity (Defaults *self); +diff -Naur old_src/display.c src/display.c +--- old_src/display.c 2012-03-23 10:49:59.000000000 -0400 ++++ src/display.c 2012-11-10 08:44:21.000000000 -0500 +@@ -60,12 +60,13 @@ + static gboolean + stack_is_at_top_corner (Stack *self, Bubble *bubble) + { ++ GdkScreen* screen; + gint x, y1, y2; + + g_assert (IS_STACK (self)); + g_assert (IS_BUBBLE (bubble)); + +- defaults_get_top_corner (self->defaults, &x, &y1); ++ defaults_get_top_corner (self->defaults, &screen, &x, &y1); + bubble_get_position (bubble, &x, &y2); + + return y1 == y2; +@@ -74,11 +75,12 @@ + static void + stack_display_position_sync_bubble (Stack *self, Bubble *bubble) + { +- Defaults* d = self->defaults; +- gint y = 0; +- gint x = 0; ++ Defaults* d = self->defaults; ++ GdkScreen* screen; ++ gint y = 0; ++ gint x = 0; + +- defaults_get_top_corner (d, &x, &y); ++ defaults_get_top_corner (d, &screen, &x, &y); + + // TODO: with multi-head, in focus follow mode, there may be enough + // space left on the top monitor +@@ -279,10 +281,11 @@ + static void + stack_layout (Stack* self) + { +- Bubble* bubble = NULL; +- Defaults* d; +- gint y = 0; +- gint x = 0; ++ Bubble* bubble = NULL; ++ Defaults* d; ++ GdkScreen* screen; ++ gint y = 0; ++ gint x = 0; + + g_return_if_fail (self != NULL); + +@@ -310,10 +313,12 @@ + return; + } + ++ /* + bubble_set_timeout (bubble, + defaults_get_on_screen_timeout (self->defaults)); ++ */ + +- defaults_get_top_corner (self->defaults, &x, &y); ++ defaults_get_top_corner (self->defaults, &screen, &x, &y); + + d = self->defaults; + +diff -Naur old_src/main.c src/main.c +--- old_src/main.c 2012-03-23 10:49:59.000000000 -0400 ++++ src/main.c 2012-11-10 08:44:21.000000000 -0500 +@@ -25,6 +25,10 @@ + ** with this program. If not, see <http://www.gnu.org/licenses/>. + ** + *******************************************************************************/ ++#define _GNU_SOURCE /* getline */ ++#include <unistd.h> /* getuid */ ++#include <pwd.h> /* getpwuid */ ++#include <sys/types.h> + + #include <string.h> + #include <stdlib.h> +@@ -39,6 +43,213 @@ + + #define ICONS_DIR (DATADIR G_DIR_SEPARATOR_S "notify-osd" G_DIR_SEPARATOR_S "icons") + ++/* begin hack */ ++extern float TEXT_TITLE_COLOR_R; ++extern float TEXT_TITLE_COLOR_G; ++extern float TEXT_TITLE_COLOR_B; ++extern float TEXT_TITLE_COLOR_A; ++ ++extern float TEXT_BODY_COLOR_R; ++extern float TEXT_BODY_COLOR_G; ++extern float TEXT_BODY_COLOR_B; ++extern float TEXT_BODY_COLOR_A; ++ ++extern float TEXT_SHADOW_COLOR_A; ++ ++extern float BUBBLE_BG_COLOR_R; ++extern float BUBBLE_BG_COLOR_G; ++extern float BUBBLE_BG_COLOR_B; ++extern float BUBBLE_BG_COLOR_A; ++ ++extern float DEFAULT_TEXT_TITLE_SIZE; ++extern float DEFAULT_TEXT_BODY_SIZE; ++extern float DEFAULT_ON_SCREEN_TIMEOUT; ++ ++extern short DEFAULT_TEXT_TITLE_WEIGHT; ++extern short DEFAULT_TEXT_BODY_WEIGHT; ++extern short SLOT_ALLOCATION; ++ ++extern float DEFAULT_MARGIN_SIZE; ++extern float DEFAULT_BUBBLE_CORNER_RADIUS; ++extern float DEFAULT_BUBBLE_WIDTH; ++extern float DEFAULT_BUBBLE_VERT_GAP; ++extern float DEFAULT_BUBBLE_HORZ_GAP; ++extern float DEFAULT_ICON_SIZE; ++extern float DEFAULT_GAUGE_SIZE; ++ ++extern gboolean BUBBLE_PREVENT_FADE; ++extern gboolean BUBBLE_CLOSE_ON_CLICK; ++extern gboolean BUBBLE_AS_DESKTOP_BG; ++ ++void parse_color(unsigned int c, float* r, float* g, float* b) ++{ ++ *b = (float)(c & 0xFF) / (float)(0xFF); ++ c >>= 8; ++ *g = (float)(c & 0xFF) / (float)(0xFF); ++ c >>= 8; ++ *r = (float)(c & 0xFF) / (float)(0xFF); ++} ++ ++ ++void load_settings(void) ++{ ++ char file[PATH_MAX]; ++ uid_t uid = getuid(); ++ const char* settings_file_name = ".notify-osd"; ++ ++ struct passwd* pw = getpwuid(uid); ++ if (!pw) { ++ fprintf(stderr, ++ "failed to retrieve home directory. using default settings.\n"); ++ return; ++ } ++ /* $HOME/.notify-osd */ ++ snprintf(file, sizeof(file), "%s%s%s", pw->pw_dir, ++ G_DIR_SEPARATOR_S, settings_file_name); ++ ++ FILE* fp = fopen(file, "r"); ++ ++ if (!fp) { ++ fprintf(stderr, "could not open '%s'. using default settings.\n", file); ++ return; ++ ++ } ++ printf("reading settings from '%s'\n", file); ++ ++ char* buf = NULL; ++ size_t size = 0; ++ char key[32], value[32]; ++ float fvalue; ++ unsigned int ivalue; ++ ++ while(getline(&buf, &size, fp) != -1) { ++ if (sscanf(buf, "%31s = %31s", key, value) != 2) ++ continue; ++ if (!strcmp(key, "bubble-background-color") && ++ sscanf(value, "%x", &ivalue)) { ++ ++ parse_color(ivalue, &BUBBLE_BG_COLOR_R, &BUBBLE_BG_COLOR_G, ++ &BUBBLE_BG_COLOR_B); ++ ++ ++ } else if (!strcmp(key, "bubble-background-opacity") && ++ sscanf(value, "%f", &fvalue)) { ++ ++ BUBBLE_BG_COLOR_A = fvalue*0.01; ++ ++ } else if (!strcmp(key, "text-title-color") && ++ sscanf(value, "%x", &ivalue) ) { ++ ++ parse_color(ivalue, &TEXT_TITLE_COLOR_R, &TEXT_TITLE_COLOR_G, ++ &TEXT_TITLE_COLOR_B); ++ ++ } else if (!strcmp(key, "text-title-opacity") && ++ sscanf(value, "%f", &fvalue) ) { ++ ++ TEXT_TITLE_COLOR_A = fvalue*0.01; ++ ++ } else if (!strcmp(key, "text-body-color") && ++ sscanf(value, "%x", &ivalue) ) { ++ ++ parse_color(ivalue, &TEXT_BODY_COLOR_R, &TEXT_BODY_COLOR_G, ++ &TEXT_BODY_COLOR_B); ++ ++ } else if (!strcmp(key, "text-body-opacity") && ++ sscanf(value, "%f", &fvalue) ) { ++ ++ TEXT_BODY_COLOR_A = fvalue*0.01; ++ ++ } else if (!strcmp(key, "text-shadow-opacity") && ++ sscanf(value, "%f", &fvalue) ) { ++ ++ TEXT_SHADOW_COLOR_A = fvalue*0.01; ++ ++ } else if (!strcmp(key, "text-title-size") && ++ sscanf(value, "%f", &fvalue) ) { ++ DEFAULT_TEXT_TITLE_SIZE = fvalue*0.01; ++ ++ } else if (!strcmp(key, "text-body-size") && ++ sscanf(value, "%f", &fvalue) ) { ++ DEFAULT_TEXT_BODY_SIZE = fvalue*0.01; ++ ++ } else if (!strcmp(key, "bubble-expire-timeout") && ++ sscanf(value, "%f", &fvalue) ) { ++ DEFAULT_ON_SCREEN_TIMEOUT = fvalue*1000; ++ ++ } else if (!strcmp(key, "text-title-weight")) { ++ if (!strcmp(value, "bold")) { ++ DEFAULT_TEXT_TITLE_WEIGHT = 700; ++ } else if (!strcmp(value, "normal")) { ++ DEFAULT_TEXT_TITLE_WEIGHT = 400; ++ } else if (!strcmp(value, "light")) { ++ DEFAULT_TEXT_TITLE_WEIGHT = 300; ++ } ++ } else if (!strcmp(key, "text-body-weight")) { ++ if (!strcmp(value, "bold")) { ++ DEFAULT_TEXT_BODY_WEIGHT = 700; ++ } else if (!strcmp(value, "normal")) { ++ DEFAULT_TEXT_BODY_WEIGHT = 400; ++ } else if (!strcmp(value, "light")) { ++ DEFAULT_TEXT_BODY_WEIGHT = 300; ++ } ++ } else if (!strcmp(key, "text-margin-size") && ++ sscanf(value, "%f", &fvalue) ) { ++ DEFAULT_MARGIN_SIZE = fvalue*0.1; ++ ++ } else if (!strcmp(key, "bubble-corner-radius") && ++ sscanf(value, "%f", &fvalue) ) { ++ DEFAULT_BUBBLE_CORNER_RADIUS = fvalue*0.01; ++ ++ } else if (!strcmp(key, "bubble-width") && ++ sscanf(value, "%f", &fvalue) ) { ++ DEFAULT_BUBBLE_WIDTH = fvalue*0.1; ++ ++ } else if (!strcmp(key, "slot-allocation")) { ++ if (!strcmp(value, "dynamic")) { ++ SLOT_ALLOCATION = SLOT_ALLOCATION_DYNAMIC; ++ } else if (!strcmp(value, "fixed")) { ++ SLOT_ALLOCATION = SLOT_ALLOCATION_FIXED; ++ } ++ } else if (!strcmp(key, "bubble-vertical-gap") && ++ sscanf(value, "%f", &fvalue) ) { ++ DEFAULT_BUBBLE_VERT_GAP = fvalue*0.1; ++ ++ } else if (!strcmp(key, "bubble-horizontal-gap") && ++ sscanf(value, "%f", &fvalue) ) { ++ DEFAULT_BUBBLE_HORZ_GAP = fvalue*0.1; ++ ++ } else if (!strcmp(key, "bubble-icon-size") && ++ sscanf(value, "%f", &fvalue) ) { ++ DEFAULT_ICON_SIZE = fvalue*0.1; ++ ++ } else if (!strcmp(key, "bubble-gauge-size") && ++ sscanf(value, "%f", &fvalue) ) { ++ DEFAULT_GAUGE_SIZE = fvalue*0.1; ++ ++ } else if (!strcmp(key, "bubble-prevent-fade") && ++ sscanf(value, "%d", &ivalue) ) { ++ BUBBLE_PREVENT_FADE = ivalue; ++ ++ } else if (!strcmp(key, "bubble-close-on-click") && ++ sscanf(value, "%d", &ivalue) ) { ++ BUBBLE_CLOSE_ON_CLICK = ivalue; ++ ++ } else if (!strcmp(key, "bubble-as-desktop-bg") && ++ sscanf(value, "%d", &ivalue) ) { ++ BUBBLE_AS_DESKTOP_BG = ivalue; ++ ++ } ++ ++ } ++ ++ if (buf) { ++ free(buf); ++ } ++ ++ fclose(fp); ++} ++/* end hack */ ++ + int + main (int argc, + char** argv) +@@ -58,6 +269,8 @@ + gtk_icon_theme_append_search_path(gtk_icon_theme_get_default(), + ICONS_DIR); + ++ load_settings(); ++ + defaults = defaults_new (); + observer = observer_new (); + stack = stack_new (defaults, observer); +diff -Naur old_src/send-test-notification.sh src/send-test-notification.sh +--- old_src/send-test-notification.sh 1969-12-31 19:00:00.000000000 -0500 ++++ src/send-test-notification.sh 2012-11-10 08:44:09.000000000 -0500 +@@ -0,0 +1,63 @@ ++#!/bin/sh ++ ++notify-send "Take note" "The next example will test the icon-only layout-case" -i dialog-info ++sleep 2 ++notify-send "Eject" -i notification-device-eject -h string:x-canonical-private-icon-only: ++sleep 2 ++notify-send "WiFi signal found" -i notification-network-wireless-medium ++sleep 2 ++notify-send "WiFi signal lost" -i notification-network-wireless-disconnected ++sleep 2 ++notify-send "Volume" -i notification-audio-volume-medium -h int:value:75 -h string:x-canonical-private-synchronous: ++sleep 2 ++notify-send "Volume" -i notification-audio-volume-low -h int:value:30 -h string:x-canonical-private-synchronous: ++sleep 2 ++notify-send "Brightness" -i notification-display-brightness-high -h int:value:101 -h string:x-canonical-private-synchronous: ++sleep 2 ++notify-send "Brightness" -i notification-keyboard-brightness-medium -h int:value:45 -h string:x-canonical-private-synchronous: ++sleep 2 ++notify-send "Testing markup" "Some <b>bold</b>, <u>underlined</u>, <i>italic</i> text. Note, you should not see any marked up text." ++sleep 2 ++notify-send "Jamshed Kakar" "Hey, what about this restaurant? http://www.blafasel.org ++ ++Would you go from your place by train or should I pick you up from work? What do you think?" ++sleep 2 ++notify-send "English bubble" "The quick brown fox jumps over the lazy dog." -i network ++sleep 2 ++notify-send "Bubble from Germany" "Polyfon zwitschernd aßen Mäxchens Vögel Rüben, Joghurt und Quark." -i gnome-system ++sleep 2 ++notify-send "Very russian" "Съешь ещё этих мягких французских булок, да выпей чаю." -i dialog-info ++sleep 2 ++notify-send "More from Germany" "Oje, Qualm verwölkt Dix zig Farbtriptychons." -i gnome-globe ++sleep 2 ++notify-send "Filter the world 1/3" "<a href=\"http://www.ubuntu.com/\">Ubuntu</a> ++Don't rock the boat ++Kick him while he's down ++\"Film spectators are quiet vampires.\" ++Peace & Love ++War & Peace ++Law & Order ++Love & War ++7 > 3 ++7 > 3" ++sleep 2 ++notify-send "Filter the world 2/3" "7 > 3 ++7 > 3 ++14 < 42 ++14 < 42 ++14 < 42 ++14 < 42 ++>< ++<> ++< this is not a tag > ++<i>Not italic</i>" ++sleep 2 ++notify-send "Filter the world 3/3" "<b>So broken</i> ++<img src=\"foobar.png\" />Nothing to see ++<u>Test</u> ++<b>Bold</b> ++<span>Span</span> ++<s>E-flat</s> ++<sub>Sandwich</sub> ++<small>Fry</small> ++<tt>Testing tag</tt>" +diff -Naur old_src/stack.c src/stack.c +--- old_src/stack.c 2012-03-23 10:49:59.000000000 -0400 ++++ src/stack.c 2012-11-10 08:44:21.000000000 -0500 +@@ -44,6 +44,7 @@ + G_DEFINE_TYPE (Stack, stack, G_TYPE_OBJECT); + + #define FORCED_SHUTDOWN_THRESHOLD 500 ++#define NOTIFY_EXPIRES_DEFAULT -1 + + /* fwd declaration */ + void close_handler (GObject* n, Stack* stack); +@@ -646,6 +647,15 @@ + if (body) + bubble_set_message_body (bubble, body); + ++ if (timeout == NOTIFY_EXPIRES_DEFAULT) { ++ bubble_set_timeout (bubble, ++ defaults_get_on_screen_timeout (self->defaults)); ++ } ++ else { ++ bubble_set_timeout (bubble, timeout); ++ } ++ ++ + if (new_bubble && bubble_is_append_allowed(bubble)) { + app_bubble = find_bubble_for_append(self, bubble); + +@@ -885,6 +895,9 @@ + gint* x, + gint* y) + { ++ GdkScreen* screen = NULL; ++ gboolean is_composited = FALSE; ++ + // sanity checks + if (!x && !y) + return; +@@ -904,7 +917,9 @@ + } + + // initialize x and y +- defaults_get_top_corner (self->defaults, x, y); ++ defaults_get_top_corner (self->defaults, &screen, x, y); ++ ++ is_composited = gdk_screen_is_composited (screen); + + // differentiate returned top-left corner for top and bottom slot + // depending on the placement +@@ -920,12 +935,12 @@ + *y += defaults_get_desktop_height (d) / 2 - + EM2PIXELS (defaults_get_bubble_vert_gap (d) / 2.0f, d) - + bubble_height + +- EM2PIXELS (defaults_get_bubble_shadow_size (d), d); ++ EM2PIXELS (defaults_get_bubble_shadow_size (d, is_composited), d); + // the position for the async. bubble + else if (slot == SLOT_BOTTOM) + *y += defaults_get_desktop_height (d) / 2 + + EM2PIXELS (defaults_get_bubble_vert_gap (d) / 2.0f, d) - +- EM2PIXELS (defaults_get_bubble_shadow_size (d), d); ++ EM2PIXELS (defaults_get_bubble_shadow_size (d, is_composited), d); + break; + + case GRAVITY_NORTH_EAST: +@@ -944,15 +959,61 @@ + case SLOT_ALLOCATION_FIXED: + *y += EM2PIXELS (defaults_get_icon_size (d), d) + + 2 * EM2PIXELS (defaults_get_margin_size (d), d) + +- EM2PIXELS (defaults_get_bubble_vert_gap (d), d); /* + +- 2 * EM2PIXELS (defaults_get_bubble_shadow_size (d), d);*/ ++ EM2PIXELS (defaults_get_bubble_vert_gap (d), d) + 2; ++ break; ++ ++ case SLOT_ALLOCATION_DYNAMIC: ++ g_assert (stack_is_slot_vacant (self, SLOT_TOP) == OCCUPIED); ++ *y += bubble_get_height (self->slots[SLOT_TOP]) + ++ EM2PIXELS (defaults_get_bubble_vert_gap (d), d) - ++ 2 * EM2PIXELS (defaults_get_bubble_shadow_size (d, is_composited), d); ++ break; ++ ++ default: ++ break; ++ } ++ ++ } ++ break; ++ ++ case GRAVITY_WEST: ++ d = self->defaults; ++ ++ *x = defaults_get_desktop_left (d); ++ ++ // the position for the sync./feedback bubble ++ if (slot == SLOT_TOP) ++ *y += defaults_get_desktop_height (d) / 2 - ++ EM2PIXELS (defaults_get_bubble_vert_gap (d) / 2.0f, d) - ++ bubble_height + ++ EM2PIXELS (defaults_get_bubble_shadow_size (d, is_composited), d); ++ // the position for the async. bubble ++ else if (slot == SLOT_BOTTOM) ++ *y += defaults_get_desktop_height (d) / 2 + ++ EM2PIXELS (defaults_get_bubble_vert_gap (d) / 2.0f, d) - ++ EM2PIXELS (defaults_get_bubble_shadow_size (d, is_composited), d); ++ break; ++ ++ case GRAVITY_NORTH_WEST: ++ d = self->defaults; ++ ++ *x = defaults_get_desktop_left (d); ++ ++ if (slot == SLOT_BOTTOM) ++ { ++ switch (defaults_get_slot_allocation (d)) ++ { ++ case SLOT_ALLOCATION_FIXED: ++ *y += EM2PIXELS (defaults_get_icon_size (d), d) + ++ 2 * EM2PIXELS (defaults_get_margin_size (d), d) + ++ EM2PIXELS (defaults_get_bubble_vert_gap (d), d) + 2; + break; + + case SLOT_ALLOCATION_DYNAMIC: + g_assert (stack_is_slot_vacant (self, SLOT_TOP) == OCCUPIED); + *y += bubble_get_height (self->slots[SLOT_TOP]) + + EM2PIXELS (defaults_get_bubble_vert_gap (d), d) - +- 2 * EM2PIXELS (defaults_get_bubble_shadow_size (d), d); ++ 2 * EM2PIXELS (defaults_get_bubble_shadow_size (d, is_composited), d); + break; + + default: +@@ -961,6 +1022,114 @@ + + } + break; ++ ++ case GRAVITY_SOUTH_EAST: ++ d = self->defaults; ++ ++ switch (defaults_get_slot_allocation (d)) ++ { ++ case SLOT_ALLOCATION_FIXED: ++ if (slot == SLOT_TOP) ++ { ++ *y += defaults_get_desktop_height (d) - ++ 2 * EM2PIXELS (defaults_get_bubble_vert_gap (d), d) - ++ bubble_height + ++ 2 * EM2PIXELS (defaults_get_bubble_shadow_size (d, is_composited), d); ++ ++ } ++ ++ if (slot == SLOT_BOTTOM) ++ { ++ *y += defaults_get_desktop_height (d) - ++ bubble_height - ++ EM2PIXELS (defaults_get_icon_size (d), d) - ++ 2 * EM2PIXELS (defaults_get_margin_size (d), d) - ++ 3 * EM2PIXELS (defaults_get_bubble_vert_gap (d), d) + ++ 2 * EM2PIXELS (defaults_get_bubble_shadow_size (d, is_composited), d) - 2; ++ ++ } ++ break; ++ ++ case SLOT_ALLOCATION_DYNAMIC: ++ if (slot == SLOT_TOP) ++ { ++ *y += defaults_get_desktop_height (d) - ++ 2 * EM2PIXELS (defaults_get_bubble_vert_gap (d), d) - ++ bubble_height + ++ 2 * EM2PIXELS (defaults_get_bubble_shadow_size (d, is_composited), d); ++ } ++ ++ if (slot == SLOT_BOTTOM) ++ { ++ g_assert (stack_is_slot_vacant (self, SLOT_TOP) == OCCUPIED); ++ *y += defaults_get_desktop_height (d) - ++ 3 * EM2PIXELS (defaults_get_bubble_vert_gap (d), d) - ++ bubble_height + ++ 4 * EM2PIXELS (defaults_get_bubble_shadow_size (d, is_composited), d) - ++ bubble_get_height (self->slots[SLOT_TOP]); ++ } ++ break; ++ ++ default: ++ break; ++ } ++ ++ break; ++ ++ case GRAVITY_SOUTH_WEST: ++ d = self->defaults; ++ ++ *x = defaults_get_desktop_left (d); ++ ++ switch (defaults_get_slot_allocation (d)) ++ { ++ case SLOT_ALLOCATION_FIXED: ++ if (slot == SLOT_TOP) ++ { ++ *y += defaults_get_desktop_height (d) - ++ 2 * EM2PIXELS (defaults_get_bubble_vert_gap (d), d) - ++ bubble_height + ++ 2 * EM2PIXELS (defaults_get_bubble_shadow_size (d, is_composited), d); ++ ++ } ++ ++ if (slot == SLOT_BOTTOM) ++ { ++ *y += defaults_get_desktop_height (d) - ++ bubble_height - ++ EM2PIXELS (defaults_get_icon_size (d), d) - ++ 2 * EM2PIXELS (defaults_get_margin_size (d), d) - ++ 3 * EM2PIXELS (defaults_get_bubble_vert_gap (d), d) + ++ 2 * EM2PIXELS (defaults_get_bubble_shadow_size (d, is_composited), d) - 2; ++ ++ } ++ break; ++ ++ case SLOT_ALLOCATION_DYNAMIC: ++ if (slot == SLOT_TOP) ++ { ++ *y += defaults_get_desktop_height (d) - ++ 2 * EM2PIXELS (defaults_get_bubble_vert_gap (d), d) - ++ bubble_height + ++ 2 * EM2PIXELS (defaults_get_bubble_shadow_size (d, is_composited), d); ++ } ++ ++ if (slot == SLOT_BOTTOM) ++ { ++ g_assert (stack_is_slot_vacant (self, SLOT_TOP) == OCCUPIED); ++ *y += defaults_get_desktop_height (d) - ++ 3 * EM2PIXELS (defaults_get_bubble_vert_gap (d), d) - ++ bubble_height + ++ 4 * EM2PIXELS (defaults_get_bubble_shadow_size (d, is_composited), d) - ++ bubble_get_height (self->slots[SLOT_TOP]); ++ } ++ break; ++ ++ default: ++ break; ++ } ++ ++ break; + + default: + g_warning ("Unhandled placement!\n"); |