Commit a0134c70 authored by Alberts Muktupāvels's avatar Alberts Muktupāvels
Browse files

common: add GfPopupWindow

parent 25630292
......@@ -14,6 +14,8 @@ libcommon_la_CFLAGS = \
libcommon_la_SOURCES = \
gf-keybindings.c \
gf-keybindings.h \
gf-popup-window.c \
gf-popup-window.h \
$(NULL)
libcommon_la_LDFLAGS = \
......
/*
* Copyright (C) 2015 Alberts Muktupāvels
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "gf-popup-window.h"
typedef struct _GfPopupWindowPrivate GfPopupWindowPrivate;
struct _GfPopupWindowPrivate
{
guint fade_id;
};
enum
{
SIGNAL_FADE_FINISHED,
LAST_SIGNAL
};
static guint signals[LAST_SIGNAL] = { 0 };
G_DEFINE_TYPE_WITH_PRIVATE (GfPopupWindow, gf_popup_window, GTK_TYPE_WINDOW)
static gboolean
fade_out_cb (gpointer user_data)
{
GfPopupWindow *window;
GfPopupWindowPrivate *priv;
GtkWidget *widget;
gdouble opacity;
window = GF_POPUP_WINDOW (user_data);
priv = gf_popup_window_get_instance_private (window);
widget = GTK_WIDGET (window);
opacity = gtk_widget_get_opacity (widget);
opacity -= 0.02;
if (opacity <= 0.00)
{
gtk_widget_set_opacity (widget, 1.0);
g_signal_emit (window, signals[SIGNAL_FADE_FINISHED], 0);
priv->fade_id = 0;
return G_SOURCE_REMOVE;
}
gtk_widget_set_opacity (widget, opacity);
gtk_widget_queue_draw (widget);
return G_SOURCE_CONTINUE;
}
static void
gf_popup_window_finalize (GObject *object)
{
GfPopupWindow *window;
GfPopupWindowPrivate *priv;
window = GF_POPUP_WINDOW (object);
priv = gf_popup_window_get_instance_private (window);
if (priv->fade_id > 0)
{
g_source_remove (priv->fade_id);
priv->fade_id = 0;
}
G_OBJECT_CLASS (gf_popup_window_parent_class)->finalize (object);
}
static cairo_surface_t *
get_background_surface (GtkWidget *widget,
cairo_t *cr,
gint width,
gint height)
{
cairo_surface_t *surface;
cairo_t *cr_local;
GtkStyleContext *context;
surface = cairo_surface_create_similar (cairo_get_target (cr),
CAIRO_CONTENT_COLOR_ALPHA,
width, height);
if (cairo_surface_status (surface) != CAIRO_STATUS_SUCCESS)
{
if (surface)
cairo_surface_destroy (surface);
return NULL;
}
cr_local = cairo_create (surface);
if (cairo_status (cr_local) != CAIRO_STATUS_SUCCESS)
{
cairo_surface_destroy (surface);
if (cr_local)
cairo_destroy (cr_local);
return NULL;
}
context = gtk_widget_get_style_context (widget);
gtk_render_background (context, cr_local, 0, 0, width, height);
gtk_render_frame (context, cr_local, 0, 0, width, height);
cairo_destroy (cr_local);
return surface;
}
static gboolean
gf_popup_window_draw (GtkWidget *widget,
cairo_t *cr)
{
gint width;
gint height;
cairo_surface_t *surface;
width = gtk_widget_get_allocated_width (widget);
height = gtk_widget_get_allocated_height (widget);
surface = get_background_surface (widget, cr, width, height);
if (surface == NULL)
return TRUE;
cairo_rectangle (cr, 0, 0, width, height);
cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.0);
cairo_fill (cr);
cairo_set_source_surface (cr, surface, 0, 0);
cairo_paint (cr);
cairo_surface_destroy (surface);
return GTK_WIDGET_CLASS (gf_popup_window_parent_class)->draw (widget, cr);
}
static void
gf_popup_window_realize (GtkWidget *widget)
{
GdkScreen *screen;
GdkVisual *visual;
screen = gtk_widget_get_screen (widget);
visual = gdk_screen_get_rgba_visual (screen);
if (visual == NULL)
visual = gdk_screen_get_system_visual (screen);
gtk_widget_set_visual (widget, visual);
GTK_WIDGET_CLASS (gf_popup_window_parent_class)->realize (widget);
}
static void
gf_popup_window_class_init (GfPopupWindowClass *window_class)
{
GObjectClass *object_class;
GtkWidgetClass *widget_class;
object_class = G_OBJECT_CLASS (window_class);
widget_class = GTK_WIDGET_CLASS (window_class);
object_class->finalize = gf_popup_window_finalize;
widget_class->draw = gf_popup_window_draw;
widget_class->realize = gf_popup_window_realize;
signals[SIGNAL_FADE_FINISHED] =
g_signal_new ("fade-finished", G_OBJECT_CLASS_TYPE (window_class),
G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0);
}
static void
gf_popup_window_init (GfPopupWindow *window)
{
GtkWindow *gtk_window;
GtkWidget *widget;
gtk_window = GTK_WINDOW (window);
widget = GTK_WIDGET (window);
gtk_window_set_decorated (gtk_window, FALSE);
gtk_window_set_focus_on_map (gtk_window, FALSE);
gtk_window_set_type_hint (gtk_window, GDK_WINDOW_TYPE_HINT_NOTIFICATION);
gtk_window_set_skip_pager_hint (gtk_window, TRUE);;
gtk_window_set_skip_taskbar_hint (gtk_window, TRUE);
gtk_widget_set_app_paintable (widget, TRUE);
}
void
gf_popup_window_fade_start (GfPopupWindow *window)
{
GfPopupWindowPrivate *priv;
GtkWidget *widget;
priv = gf_popup_window_get_instance_private (window);
widget = GTK_WIDGET (window);
if (priv->fade_id != 0)
g_source_remove (priv->fade_id);
gtk_widget_set_opacity (widget, 1.0);
priv->fade_id = g_timeout_add (10, fade_out_cb, window);
g_source_set_name_by_id (priv->fade_id, "[gnome-flashback] fade_out_cb");
}
void
gf_popup_window_fade_cancel (GfPopupWindow *window)
{
GfPopupWindowPrivate *priv;
GtkWidget *widget;
priv = gf_popup_window_get_instance_private (window);
widget = GTK_WIDGET (window);
if (priv->fade_id != 0)
{
g_source_remove (priv->fade_id);
priv->fade_id = 0;
}
gtk_widget_set_opacity (widget, 1.0);
}
/*
* Copyright (C) 2015 Alberts Muktupāvels
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef GF_POPUP_WINDOW_H
#define GF_POPUP_WINDOW_H
#include <gtk/gtk.h>
G_BEGIN_DECLS
#define GF_TYPE_POPUP_WINDOW gf_popup_window_get_type ()
G_DECLARE_DERIVABLE_TYPE (GfPopupWindow, gf_popup_window,
GF, POPUP_WINDOW, GtkWindow)
struct _GfPopupWindowClass
{
GtkWindowClass parent_class;
};
void gf_popup_window_fade_start (GfPopupWindow *window);
void gf_popup_window_fade_cancel (GfPopupWindow *window);
G_END_DECLS
#endif
......@@ -21,152 +21,32 @@
#include "flashback-label-window.h"
#define HIDE_TIMEOUT 1500
#define FADE_TIMEOUT 10
struct _FlashbackLabelWindow
{
GtkWindow parent;
GfPopupWindow parent;
GdkRectangle monitor;
GdkRectangle monitor;
guint hide_timeout_id;
guint fade_timeout_id;
guint hide_timeout_id;
gdouble fade_out_alpha;
GtkWidget *label;
GtkWidget *label;
};
G_DEFINE_TYPE (FlashbackLabelWindow, flashback_label_window, GTK_TYPE_WINDOW)
static cairo_surface_t *
flashback_label_window_draw_real (FlashbackLabelWindow *window,
cairo_t *cr1,
gint width,
gint height)
{
cairo_surface_t *surface;
cairo_t *cr2;
GtkStyleContext *context;
surface = cairo_surface_create_similar (cairo_get_target (cr1),
CAIRO_CONTENT_COLOR_ALPHA,
width, height);
if (cairo_surface_status (surface) != CAIRO_STATUS_SUCCESS)
{
if (surface)
cairo_surface_destroy (surface);
return NULL;
}
cr2 = cairo_create (surface);
if (cairo_status (cr2) != CAIRO_STATUS_SUCCESS)
{
cairo_surface_destroy (surface);
return NULL;
}
context = gtk_widget_get_style_context (GTK_WIDGET (window));
gtk_render_background (context, cr2, 0, 0, width, height);
gtk_render_frame (context, cr2, 0, 0, width, height);
cairo_destroy (cr2);
return surface;
}
static gboolean
flashback_label_window_draw (GtkWidget *widget,
cairo_t *cr)
{
FlashbackLabelWindow *window;
gint width;
gint height;
cairo_surface_t *surface;
window = FLASHBACK_LABEL_WINDOW (widget);
gtk_window_get_size (GTK_WINDOW (widget), &width, &height);
surface = flashback_label_window_draw_real (window, cr, width, height);
if (surface == NULL)
return TRUE;
cairo_rectangle (cr, 0, 0, width, height);
cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.0);
cairo_fill (cr);
cairo_set_source_surface (cr, surface, 0, 0);
cairo_paint_with_alpha (cr, window->fade_out_alpha);
cairo_surface_destroy (surface);
return GTK_WIDGET_CLASS (flashback_label_window_parent_class)->draw (widget, cr);
}
static gboolean
fade_timeout_cb (gpointer user_data)
{
FlashbackLabelWindow *window;
window = FLASHBACK_LABEL_WINDOW (user_data);
if (window->fade_out_alpha <= 0.0)
{
window->fade_timeout_id = 0;
gtk_widget_destroy (GTK_WIDGET (window));
return FALSE;
}
window->fade_out_alpha -= 0.10;
gtk_widget_queue_draw (GTK_WIDGET (window));
return TRUE;
}
G_DEFINE_TYPE (FlashbackLabelWindow, flashback_label_window,
GF_TYPE_POPUP_WINDOW)
static void
remove_fade_timeout (FlashbackLabelWindow *window)
fade_finished_cb (GfPopupWindow *window)
{
if (window->fade_timeout_id > 0)
{
g_source_remove (window->fade_timeout_id);
window->fade_timeout_id = 0;
window->fade_out_alpha = 1.0;
}
}
static void
flashback_label_window_finalize (GObject *object)
{
FlashbackLabelWindow *window;
window = FLASHBACK_LABEL_WINDOW (object);
remove_fade_timeout (window);
G_OBJECT_CLASS (flashback_label_window_parent_class)->finalize (object);
gtk_widget_destroy (GTK_WIDGET (window));
}
static void
flashback_label_window_realize (GtkWidget *widget)
{
GdkScreen *screen;
GdkVisual *visual;
cairo_region_t *region;
screen = gtk_widget_get_screen (widget);
visual = gdk_screen_get_rgba_visual (screen);
if (visual == NULL)
visual = gdk_screen_get_system_visual (screen);
gtk_widget_set_visual (widget, visual);
GTK_WIDGET_CLASS (flashback_label_window_parent_class)->realize (widget);
region = cairo_region_create ();
......@@ -177,15 +57,10 @@ flashback_label_window_realize (GtkWidget *widget)
static void
flashback_label_window_class_init (FlashbackLabelWindowClass *window_class)
{
GObjectClass *object_class;
GtkWidgetClass *widget_class;
object_class = G_OBJECT_CLASS (window_class);
widget_class = GTK_WIDGET_CLASS (window_class);
object_class->finalize = flashback_label_window_finalize;
widget_class->draw = flashback_label_window_draw;
widget_class->realize = flashback_label_window_realize;
}
......@@ -194,8 +69,6 @@ flashback_label_window_init (FlashbackLabelWindow *window)
{
GtkWidget *box;
window->fade_out_alpha = 1.0;
box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 10);
gtk_container_set_border_width (GTK_CONTAINER (window), 20);
gtk_container_add (GTK_CONTAINER (window), box);
......@@ -206,6 +79,9 @@ flashback_label_window_init (FlashbackLabelWindow *window)
gtk_widget_set_valign (window->label, GTK_ALIGN_CENTER);
gtk_box_pack_start (GTK_BOX (box), window->label, TRUE, FALSE, 0);
gtk_widget_show (window->label);
g_signal_connect (window, "fade-finished",
G_CALLBACK (fade_finished_cb), NULL);
}
FlashbackLabelWindow *
......@@ -221,12 +97,6 @@ flashback_label_window_new (gint monitor,
screen = gdk_screen_get_default ();
window = g_object_new (FLASHBACK_TYPE_LABEL_WINDOW,
"type", GTK_WINDOW_POPUP,
"type-hint", GDK_WINDOW_TYPE_HINT_NOTIFICATION,
"app-paintable", TRUE,
"decorated", FALSE,
"skip-taskbar-hint", TRUE,
"skip-pager-hint", TRUE,
"focus-on-map", FALSE,
NULL);
gdk_screen_get_monitor_workarea (screen, monitor, &window->monitor);
......@@ -268,13 +138,12 @@ flashback_label_window_show (FlashbackLabelWindow *window)
gtk_window_move (GTK_WINDOW (window), x, y);
gtk_widget_show (GTK_WIDGET (window));
remove_fade_timeout (window);
gf_popup_window_fade_cancel (GF_POPUP_WINDOW (window));
}
void
flashback_label_window_hide (FlashbackLabelWindow *window)
{
window->fade_timeout_id = g_timeout_add (FADE_TIMEOUT,
(GSourceFunc) fade_timeout_cb,
window);
gf_popup_window_fade_start (GF_POPUP_WINDOW (window));
}
......@@ -18,13 +18,13 @@
#ifndef FLASHBACK_LABEL_WINDOW_H
#define FLASHBACK_LABEL_WINDOW_H
#include <gtk/gtk.h>
#include <libcommon/gf-popup-window.h>
G_BEGIN_DECLS
#define FLASHBACK_TYPE_LABEL_WINDOW flashback_label_window_get_type ()
G_DECLARE_FINAL_TYPE (FlashbackLabelWindow, flashback_label_window,
FLASHBACK, LABEL_WINDOW, GtkWindow)
FLASHBACK, LABEL_WINDOW, GfPopupWindow)
FlashbackLabelWindow *flashback_label_window_new (gint monitor,
const gchar *label);
......
......@@ -21,116 +21,29 @@
#include "flashback-osd-window.h"
#define HIDE_TIMEOUT 1500
#define FADE_TIMEOUT 10
struct _FlashbackOsdWindow
{
GtkWindow parent;
GfPopupWindow parent;
GdkRectangle monitor;
GdkRectangle monitor;
guint hide_timeout_id;
guint fade_timeout_id;
guint hide_timeout_id;
gdouble fade_out_alpha;
GtkWidget *icon_image;
gint icon_size;
GtkWidget *icon_image;
gint icon_size;
GtkWidget *label;
GtkWidget *label;
GtkWidget *level;
GtkWidget *level;
};
G_DEFINE_TYPE (FlashbackOsdWindow, flashback_osd_window, GTK_TYPE_WINDOW)
static cairo_surface_t *
flashback_osd_window_draw_real (FlashbackOsdWindow *window,
cairo_t *cr1,
gint width,
gint height)
{
cairo_surface_t *surface;
cairo_t *cr2;
GtkStyleContext *context;
surface = cairo_surface_create_similar (cairo_get_target (cr1),
CAIRO_CONTENT_COLOR_ALPHA,
width, height);
if (cairo_surface_status (surface) != CAIRO_STATUS_SUCCESS)
{
if (surface)
cairo_surface_destroy (surface);
return NULL;
}
cr2 = cairo_create (surface);
if (cairo_status (cr2) != CAIRO_STATUS_SUCCESS)
{
cairo_surface_destroy (surface);
return NULL;
}
context = gtk_widget_get_style_context (GTK_WIDGET (window));
gtk_render_background (context, cr2, 0, 0, width, height);
gtk_render_frame (context, cr2, 0, 0, width, height);
cairo_destroy (cr2);
return surface;
}
static gboolean
flashback_osd_window_draw (GtkWidget *widget,
cairo_t *cr)
{