Commit 2efee352 authored by Guido Gunther's avatar Guido Gunther Committed by Gogs

Merge branch 'background-image' of guido.gunther/phosh into master

parents ba1a299c 59777b6f
......@@ -5,14 +5,23 @@
* Author: Guido Günther <agx@sigxcpu.org>
*/
#include "phosh.h"
#include "background.h"
#include "phosh.h"
#include "panel.h"
#include <math.h>
#include <string.h>
enum {
BACKGROUND_LOADED,
N_SIGNALS
};
static guint signals[N_SIGNALS];
typedef struct
{
GdkPixbuf *pixbuf;
GSettings *settings;
} PhoshBackgroundPrivate;
......@@ -26,33 +35,90 @@ G_DEFINE_TYPE_WITH_PRIVATE (PhoshBackground, phosh_background, GTK_TYPE_WINDOW)
static GdkPixbuf *
scale_background (GdkPixbuf *original_pixbuf)
image_background (GdkPixbuf *image)
{
GdkDisplay *display = gdk_display_get_default ();
/* There's no primary monitor on nested wayland so just use the
first one for now */
GdkMonitor *monitor = gdk_display_get_monitor (display, 0);
GdkRectangle geom;
gint original_width, original_height;
gint orig_width, orig_height, width, height;
gint final_width, final_height;
gdouble ratio_horizontal, ratio_vertical;
/* FIXME: handle org.gnome.desktop.background gsettings */
g_return_val_if_fail(monitor, NULL);
gdk_monitor_get_geometry (monitor, &geom);
original_width = gdk_pixbuf_get_width (original_pixbuf);
original_height = gdk_pixbuf_get_height (original_pixbuf);
gint x, y, off_x, off_y;
gdouble ratio_horiz, ratio_vert, ratio;
GdkPixbuf *bg, *scaled_bg;
const gchar *xpm_data[] = {"1 1 1 1", "_ c WebGrey", "_"};
ratio_horizontal = (double) geom.width / original_width;
ratio_vertical = (double) geom.height / original_height;
phosh_shell_get_usable_area (phosh(), &x, &y, &width, &height);
bg = gdk_pixbuf_new_from_xpm_data (xpm_data);
scaled_bg = gdk_pixbuf_scale_simple (bg,
width,
/* since we can't offset the pixmap */
height + y,
GDK_INTERP_BILINEAR);
g_object_unref (bg);
/* FIXME: we should allow more modes
none, wallpaper, centered, scaled, stretched, zoom
I think GNOME calls this zoom:
*/
orig_width = gdk_pixbuf_get_width (image);
orig_height = gdk_pixbuf_get_height (image);
ratio_horiz = (double) width / orig_width;
ratio_vert = (double) height / orig_height;
ratio = ratio_horiz > ratio_vert ? ratio_vert : ratio_horiz;
final_width = ceil (ratio * orig_width);
final_height = ceil (ratio * orig_height);
off_x = (width - final_width) / 2;
off_y = (height - final_height) / 2;
gdk_pixbuf_composite (image,
scaled_bg,
off_x, off_y, /* dest x,y */
final_width,
final_height,
off_x, off_y, /* offset x, y */
ratio,
ratio,
GDK_INTERP_BILINEAR,
255);
return scaled_bg;
}
final_width = ceil (ratio_horizontal * original_width);
final_height = ceil (ratio_vertical * original_height);
return gdk_pixbuf_scale_simple (original_pixbuf,
final_width, final_height, GDK_INTERP_BILINEAR);
static void
load_background (PhoshBackground *self,
const char* uri)
{
PhoshBackgroundPrivate *priv = phosh_background_get_instance_private (self);
GdkPixbuf *image = NULL;
const gchar *xpm_data[] = {"1 1 1 1", "_ c WebGrey", "_"};
GError *err = NULL;
if (priv->pixbuf) {
g_object_unref (priv->pixbuf);
priv->pixbuf = NULL;
}
/* FIXME: support GnomeDesktop.BGSlideShow as well */
if (!g_str_has_prefix(uri, "file:///")) {
g_warning ("Only file URIs supported for backgrounds not %s", uri);
} else {
image = gdk_pixbuf_new_from_file (&uri[strlen("file://")], &err);
if (!image) {
const char *reason = err ? err->message : "unknown error";
g_warning ("Failed to load background: %s", reason);
if (err)
g_clear_error (&err);
}
}
/* Fallback if image can't be loaded */
if (!image)
image = gdk_pixbuf_new_from_xpm_data (xpm_data);
priv->pixbuf = image_background (image);
g_object_unref (image);
/* force background redraw */
gtk_widget_queue_draw (GTK_WIDGET (self));
g_signal_emit(self, signals[BACKGROUND_LOADED], 0);
}
......@@ -62,8 +128,10 @@ background_draw_cb (PhoshBackground *self,
gpointer data)
{
PhoshBackgroundPrivate *priv = phosh_background_get_instance_private (self);
gint x, y, width, height;
gdk_cairo_set_source_pixbuf (cr, priv->pixbuf, 0, 0);
phosh_shell_get_usable_area (phosh(), &x, &y, &width, &height);
gdk_cairo_set_source_pixbuf (cr, priv->pixbuf, x, y);
cairo_paint (cr);
return TRUE;
}
......@@ -73,32 +141,60 @@ static void
background_destroy_cb (GObject *object,
gpointer data)
{
/* FIXME: does this make any sense ? */
gtk_main_quit ();
}
static void
background_setting_changed_cb (GSettings *settings,
const gchar *key,
PhoshBackground *self)
{
g_autofree gchar *uri = g_settings_get_string (settings, key);
if (!uri)
return;
load_background (self, uri);
}
static void
rotation_notify_cb (PhoshBackground *self,
PhoshShell *shell)
{
PhoshBackgroundPrivate *priv = phosh_background_get_instance_private (self);
background_setting_changed_cb (priv->settings, "picture-uri", self);
}
static void
phosh_background_constructed (GObject *object)
{
PhoshBackground *self = PHOSH_BACKGROUND (object);
PhoshBackgroundPrivate *priv = phosh_background_get_instance_private (self);
GdkPixbuf *unscaled_background;
const gchar *xpm_data[] = {"1 1 1 1", "_ c WebGrey", "_"};
unscaled_background = gdk_pixbuf_new_from_xpm_data (xpm_data);
priv->pixbuf = scale_background (unscaled_background);
g_object_unref (unscaled_background);
G_OBJECT_CLASS (phosh_background_parent_class)->constructed (object);
g_signal_connect (self, "destroy", G_CALLBACK (background_destroy_cb), NULL);
g_signal_connect (self, "draw", G_CALLBACK (background_draw_cb), NULL);
priv->settings = g_settings_new ("org.gnome.desktop.background");
g_signal_connect (priv->settings, "changed::picture-uri",
G_CALLBACK (background_setting_changed_cb), self);
/* Load background initially */
background_setting_changed_cb (priv->settings, "picture-uri", self);
/* Window properties */
gtk_window_set_title (GTK_WINDOW (self), "phosh background");
gtk_window_set_decorated (GTK_WINDOW (self), FALSE);
gtk_widget_realize (GTK_WIDGET (self));
G_OBJECT_CLASS (phosh_background_parent_class)->constructed (object);
g_signal_connect_swapped (phosh(),
"notify::rotation",
G_CALLBACK (rotation_notify_cb),
self);
}
......@@ -120,6 +216,10 @@ phosh_background_class_init (PhoshBackgroundClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
signals[BACKGROUND_LOADED] = g_signal_new ("background-loaded",
G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL,
NULL, G_TYPE_NONE, 0);
object_class->constructed = phosh_background_constructed;
object_class->finalize = phosh_background_finalize;
}
......@@ -128,6 +228,10 @@ phosh_background_class_init (PhoshBackgroundClass *klass)
static void
phosh_background_init (PhoshBackground *self)
{
PhoshBackgroundPrivate *priv = phosh_background_get_instance_private (PHOSH_BACKGROUND(self));
priv->pixbuf = NULL;
priv->settings = NULL;
}
......
......@@ -27,6 +27,7 @@ static guint signals[N_SIGNALS] = { 0 };
struct PhoshPanelPrivate {
GtkWidget *btn_favorites;
GtkWidget *btn_settings;
gint height;
GnomeWallClock *wall_clock;
};
......@@ -70,6 +71,15 @@ wall_clock_notify_cb (GnomeWallClock *wall_clock,
}
static void
size_allocated_cb (PhoshPanel *self, gpointer unused)
{
gint width;
PhoshPanelPrivate *priv = phosh_panel_get_instance_private (self);
gtk_window_get_size (GTK_WINDOW (self), &width, &priv->height);
}
static void
phosh_panel_constructed (GObject *object)
{
......@@ -96,6 +106,10 @@ phosh_panel_constructed (GObject *object)
G_CALLBACK (settings_clicked_cb),
self,
G_CONNECT_SWAPPED);
g_signal_connect (self,
"size-allocate",
G_CALLBACK (size_allocated_cb),
NULL);
/* window properties */
gtk_window_set_title (GTK_WINDOW (self), "phosh panel");
......@@ -169,3 +183,11 @@ phosh_panel_new (void)
return g_object_new (PHOSH_PANEL_TYPE,
NULL);
}
gint
phosh_panel_get_height (PhoshPanel *self)
{
PhoshPanelPrivate *priv = phosh_panel_get_instance_private (self);
return priv->height;
}
......@@ -35,5 +35,6 @@ struct PhoshPanelClass
GType phosh_panel_get_type (void) G_GNUC_CONST;
GtkWidget * phosh_panel_new (void);
gint phosh_panel_get_height (PhoshPanel *self);
#endif /* PHOSH_PANEL_H */
......@@ -24,6 +24,13 @@
#include "favorites.h"
#include "settings.h"
enum {
PHOSH_SHELL_PROP_0,
PHOSH_SHELL_PROP_ROTATION,
PHOSH_SHELL_PROP_LAST_PROP
};
static GParamSpec *props[PHOSH_SHELL_PROP_LAST_PROP];
struct elem {
GtkWidget *window;
struct wl_surface *surface;
......@@ -40,6 +47,7 @@ typedef struct
struct wl_pointer *pointer;
GdkDisplay *gdk_display;
gint rotation;
/* Top panel */
struct elem *panel;
......@@ -379,6 +387,47 @@ static const struct wl_registry_listener registry_listener = {
};
static void
phosh_shell_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
PhoshShell *self = PHOSH_SHELL (object);
PhoshShellPrivate *priv = phosh_shell_get_instance_private(self);
switch (property_id) {
case PHOSH_SHELL_PROP_ROTATION:
priv->rotation = g_value_get_uint (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
phosh_shell_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
PhoshShell *self = PHOSH_SHELL (object);
PhoshShellPrivate *priv = phosh_shell_get_instance_private(self);
switch (property_id) {
case PHOSH_SHELL_PROP_ROTATION:
g_value_set_uint (value, priv->rotation);
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
phosh_shell_constructed (GObject *object)
{
......@@ -414,8 +463,9 @@ phosh_shell_constructed (GObject *object)
env_setup ();
css_setup (self);
background_create (self);
panel_create (self);
/* Create background after panel since it needs the panel's size */
background_create (self);
}
......@@ -425,6 +475,18 @@ phosh_shell_class_init (PhoshShellClass *klass)
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->constructed = phosh_shell_constructed;
object_class->set_property = phosh_shell_set_property;
object_class->get_property = phosh_shell_get_property;
props[PHOSH_SHELL_PROP_ROTATION] =
g_param_spec_string ("rotation",
"Rotation",
"Clockwise display rotation in degree",
"",
G_PARAM_READABLE | G_PARAM_EXPLICIT_NOTIFY);
g_object_class_install_properties (object_class, PHOSH_SHELL_PROP_LAST_PROP, props);
}
......@@ -434,15 +496,62 @@ phosh_shell_init (PhoshShell *self)
}
gint
phosh_shell_get_rotation (PhoshShell *self)
{
PhoshShellPrivate *priv = phosh_shell_get_instance_private (self);
return priv->rotation;
}
void
phosh_shell_rotate_display (PhoshShell *self,
guint degree)
{
PhoshShellPrivate *priv = phosh_shell_get_instance_private (self);
priv->rotation = degree;
phosh_mobile_shell_rotate_display (priv->mshell,
priv->panel->surface,
degree);
g_object_notify_by_pspec (G_OBJECT (self), props[PHOSH_SHELL_PROP_ROTATION]);
}
/**
* Returns the usable area in pixels usable by a client on the phone
* display
*/
void
phosh_shell_get_usable_area (PhoshShell *self, gint *x, gint *y, gint *width, gint *height)
{
PhoshShellPrivate *priv = phosh_shell_get_instance_private (self);
GdkDisplay *display = gdk_display_get_default ();
/* There's no primary monitor on nested wayland so just use the
first one for now */
GdkMonitor *monitor = gdk_display_get_monitor (display, 0);
GdkRectangle geom;
gint panel_height;
g_return_if_fail(monitor);
g_return_if_fail(priv->panel);
g_return_if_fail(priv->panel->window);
gdk_monitor_get_geometry (monitor, &geom);
panel_height = phosh_panel_get_height (PHOSH_PANEL (priv->panel->window));
/* GDK fails to take rotation into account
* https://bugzilla.gnome.org/show_bug.cgi?id=793618 */
if (priv->rotation != 90 && priv->rotation != 270) {
*width = geom.width;
*height = geom.height - panel_height;
} else {
*width = geom.height;
*height = geom.width - panel_height;
}
*x = 0;
*y = panel_height;
}
......
......@@ -16,5 +16,11 @@ G_DECLARE_FINAL_TYPE (PhoshShell, phosh_shell, PHOSH, SHELL, GObject)
PhoshShell * phosh (void);
void phosh_shell_rotate_display (PhoshShell *self, guint degrees);
int phosh_shell_get_rotation (PhoshShell *self);
void phosh_shell_get_usable_area (PhoshShell *self,
gint *x,
gint *y,
gint *width,
gint *height);
#endif /* PHOSH_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment