/* * Copyright (c) 2013 Tiago Vignatti * Copyright (c) 2013-2014 Collabora Ltd. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. */ #include #include #include #include #include #include "desktop-shell-client-protocol.h" #include "shell-helper-client-protocol.h" #include "maynard-resources.h" #include "app-icon.h" #include "favorites.h" #include "panel.h" extern char **environ; /* defined by libc */ #define DEFAULT_BACKGROUND "/usr/share/wallpapers/Golden_Ripples/contents/images/1920x1200.jpg" struct element { GtkWidget *window; GdkPixbuf *pixbuf; struct wl_surface *surface; }; struct desktop { struct wl_display *display; struct wl_registry *registry; struct desktop_shell *shell; struct wl_output *output; struct shell_helper *helper; GdkDisplay *gdk_display; struct element *background; struct element *panel; }; static void desktop_shell_configure (void *data, struct desktop_shell *desktop_shell, uint32_t edges, struct wl_surface *surface, int32_t width, int32_t height) { struct desktop *desktop = data; gtk_widget_set_size_request (desktop->background->window, width, height); gtk_window_resize (GTK_WINDOW (desktop->panel->window), width, MAYNARD_PANEL_HEIGHT); desktop_shell_desktop_ready (desktop->shell); } static void desktop_shell_prepare_lock_surface (void *data, struct desktop_shell *desktop_shell) { desktop_shell_unlock (desktop_shell); } static void desktop_shell_grab_cursor (void *data, struct desktop_shell *desktop_shell, uint32_t cursor) { } static const struct desktop_shell_listener listener = { desktop_shell_configure, desktop_shell_prepare_lock_surface, desktop_shell_grab_cursor }; static void favorite_launched_cb (MaynardPanel *panel, struct desktop *desktop) { } static void panel_create (struct desktop *desktop) { struct element *panel; GdkWindow *gdk_window; panel = malloc (sizeof *panel); memset (panel, 0, sizeof *panel); panel->window = maynard_panel_new (); g_signal_connect (panel->window, "favorite-launched", G_CALLBACK (favorite_launched_cb), desktop); /* set it up as the panel */ gdk_window = gtk_widget_get_window (panel->window); gdk_wayland_window_set_use_custom_surface (gdk_window); panel->surface = gdk_wayland_window_get_wl_surface (gdk_window); desktop_shell_set_user_data (desktop->shell, desktop); desktop_shell_set_panel (desktop->shell, desktop->output, panel->surface); desktop_shell_set_panel_position (desktop->shell, DESKTOP_SHELL_PANEL_POSITION_TOP); shell_helper_set_panel (desktop->helper, panel->surface); gtk_widget_show_all (panel->window); desktop->panel = panel; } /* Expose callback for the drawing area */ static gboolean draw_cb (GtkWidget *widget, cairo_t *cr, gpointer data) { struct desktop *desktop = data; gdk_cairo_set_source_pixbuf (cr, desktop->background->pixbuf, 0, 0); cairo_paint (cr); return TRUE; } /* Destroy handler for the window */ static void destroy_cb (GObject *object, gpointer data) { gtk_main_quit (); } static GdkPixbuf * scale_background (GdkPixbuf *original_pixbuf) { /* Scale original_pixbuf so it mostly fits on the screen. * If the aspect ratio is different than a bit on the right or on the * bottom could be cropped out. */ GdkScreen *screen = gdk_screen_get_default (); gint screen_width, screen_height; gint original_width, original_height; gint final_width, final_height; gdouble ratio_horizontal, ratio_vertical, ratio; screen_width = gdk_screen_get_width (screen); screen_height = gdk_screen_get_height (screen); original_width = gdk_pixbuf_get_width (original_pixbuf); original_height = gdk_pixbuf_get_height (original_pixbuf); ratio_horizontal = (double) screen_width / original_width; ratio_vertical = (double) screen_height / original_height; ratio = MAX (ratio_horizontal, ratio_vertical); final_width = ceil (ratio * original_width); final_height = ceil (ratio * original_height); return gdk_pixbuf_scale_simple (original_pixbuf, final_width, final_height, GDK_INTERP_BILINEAR); } static void background_create (struct desktop *desktop) { GdkWindow *gdk_window; struct element *background; const gchar *filename; GdkPixbuf *unscaled_background; background = malloc (sizeof *background); memset (background, 0, sizeof *background); filename = g_getenv ("BACKGROUND"); if (filename == NULL) filename = DEFAULT_BACKGROUND; unscaled_background = gdk_pixbuf_new_from_file (filename, NULL); if (!unscaled_background) { g_message ("Could not load background. " "Do you have kdewallpapers installed?"); exit (EXIT_FAILURE); } background->pixbuf = scale_background (unscaled_background); g_object_unref (unscaled_background); background->window = gtk_window_new (GTK_WINDOW_TOPLEVEL); g_signal_connect (background->window, "destroy", G_CALLBACK (destroy_cb), NULL); g_signal_connect (background->window, "draw", G_CALLBACK (draw_cb), desktop); gtk_window_set_title (GTK_WINDOW (background->window), "maynard"); gtk_window_set_decorated (GTK_WINDOW (background->window), FALSE); gtk_widget_realize (background->window); gdk_window = gtk_widget_get_window (background->window); gdk_wayland_window_set_use_custom_surface (gdk_window); background->surface = gdk_wayland_window_get_wl_surface (gdk_window); desktop_shell_set_user_data (desktop->shell, desktop); desktop_shell_set_background (desktop->shell, desktop->output, background->surface); desktop->background = background; gtk_widget_show_all (background->window); } static void css_setup (struct desktop *desktop) { GtkCssProvider *provider; GFile *file; GError *error = NULL; provider = gtk_css_provider_new (); file = g_file_new_for_uri ("resource:///org/raspberry-pi/maynard/style.css"); if (!gtk_css_provider_load_from_file (provider, file, &error)) { g_warning ("Failed to load CSS file: %s", error->message); g_clear_error (&error); g_object_unref (file); return; } gtk_style_context_add_provider_for_screen (gdk_screen_get_default (), GTK_STYLE_PROVIDER (provider), 600); g_object_unref (file); } static void registry_handle_global (void *data, struct wl_registry *registry, uint32_t name, const char *interface, uint32_t version) { struct desktop *d = data; if (!strcmp (interface, "desktop_shell")) { d->shell = wl_registry_bind (registry, name, &desktop_shell_interface, 3); desktop_shell_add_listener (d->shell, &listener, d); } else if (!strcmp (interface, "wl_output")) { /* TODO: create multiple outputs */ d->output = wl_registry_bind (registry, name, &wl_output_interface, 1); } else if (!strcmp (interface, "shell_helper")) { d->helper = wl_registry_bind (registry, name, &shell_helper_interface, 1); } } static void registry_handle_global_remove (void *data, struct wl_registry *registry, uint32_t name) { } static const struct wl_registry_listener registry_listener = { registry_handle_global, registry_handle_global_remove }; int main (int argc, char *argv[]) { struct desktop *desktop; gdk_set_allowed_backends ("wayland"); gtk_init (&argc, &argv); g_resources_register (maynard_get_resource ()); desktop = malloc (sizeof *desktop); desktop->output = NULL; desktop->shell = NULL; desktop->helper = NULL; desktop->gdk_display = gdk_display_get_default (); desktop->display = gdk_wayland_display_get_wl_display (desktop->gdk_display); if (desktop->display == NULL) { fprintf (stderr, "failed to get display: %m\n"); return -1; } desktop->registry = wl_display_get_registry (desktop->display); wl_registry_add_listener (desktop->registry, ®istry_listener, desktop); /* Wait until we have been notified about the compositor, * shell, and shell helper objects */ if (!desktop->output || !desktop->shell || !desktop->helper) wl_display_roundtrip (desktop->display); if (!desktop->output || !desktop->shell || !desktop->helper) { fprintf (stderr, "could not find output, shell or helper modules\n"); return -1; } css_setup (desktop); background_create (desktop); /* panel needs to be first so everything else can * be added to its layer */ panel_create (desktop); gtk_main (); /* TODO cleanup */ return EXIT_SUCCESS; }