#include #include #include "util.h" #include #include #include "msm-multiscreen.h" #include /* button responses */ enum { RESPONSE_LOG_OUT = 0, RESPONSE_RESTART = 1, RESPONSE_TURN_OFF = 2, }; typedef struct { GdkScreen *screen; int monitor; GdkRectangle iris_rect; GdkWindow *root_window; GdkPixbuf *back_pb, *dest; int percent; int pixel_size; GdkGC *iris_gc; } LogoutEffectData; static int num_iris_timeouts = 0; static void pixelize_pixbuf (GdkPixbuf *pixbuf, gint pixel_size) { gint width, height, rowstride, n_channels; gint block_width, block_height; gint i, j; gint m, n; gint p; guchar *pixels; g_assert (pixel_size > 0); pixels = gdk_pixbuf_get_pixels (pixbuf); width = gdk_pixbuf_get_width (pixbuf); height = gdk_pixbuf_get_height (pixbuf); rowstride = gdk_pixbuf_get_rowstride (pixbuf); n_channels = gdk_pixbuf_get_n_channels (pixbuf); for (i = 0; i < width; i = i + pixel_size) { for (j = 0; j < height; j = j + pixel_size) { block_width = MIN (width - i, pixel_size); block_height = MIN (height - j, pixel_size); for (m = 0; m < block_width; m ++) { for (n = 0; n < block_height; n++) { if (m == 0 && n == 0) continue; p = 0; *(pixels + (i + m )* n_channels + (j + n) * rowstride + p) = *(pixels + j*rowstride + i*n_channels + p); p++; *(pixels + (i + m )* n_channels + (j + n) * rowstride + p) = *(pixels + j*rowstride + i*n_channels + p); p++; *(pixels + (i + m )* n_channels + (j + n) * rowstride + p) = *(pixels + j*rowstride + i*n_channels + p); } } } } } static gboolean iris_callback (gpointer data) { LogoutEffectData *iris = data; if (iris->percent < 0) { g_object_unref (iris->iris_gc); g_object_unref (iris->back_pb); g_object_unref (iris->dest); g_free (iris); if (!--num_iris_timeouts) { gtk_main_quit (); } return FALSE; } pixelize_pixbuf (iris->back_pb, iris->pixel_size); gdk_pixbuf_saturate_and_pixelate (iris->back_pb, iris->dest, ((float) iris->percent) / 100.0, FALSE); gdk_draw_pixbuf (iris->root_window, iris->iris_gc, iris->dest, 0, 0, iris->iris_rect.x, iris->iris_rect.y, iris->iris_rect.width, iris->iris_rect.height, GDK_RGB_DITHER_NONE, 0, 0); gdk_flush (); iris->percent -= 30; iris->pixel_size *= 2; return TRUE; } static void run_logout_effect (GdkScreen *screen, int monitor) { GdkGCValues values; LogoutEffectData *data; data = g_new (LogoutEffectData, 1); data->screen = screen; data->monitor = monitor; data->iris_rect.x = msm_screen_get_x (screen, monitor); data->iris_rect.y = msm_screen_get_y (screen, monitor); data->iris_rect.width = msm_screen_get_width (screen, monitor); data->iris_rect.height = msm_screen_get_height (screen, monitor); data->percent = 90; data->pixel_size = 2; data->root_window = gdk_screen_get_root_window (screen); data->back_pb = gdk_pixbuf_get_from_drawable (NULL, data->root_window, NULL, data->iris_rect.x, data->iris_rect.y, 0, 0, data->iris_rect.width, data->iris_rect.height); data->dest = gdk_pixbuf_copy (data->back_pb); values.subwindow_mode = GDK_INCLUDE_INFERIORS; data->iris_gc = gdk_gc_new_with_values (data->root_window, &values, GDK_GC_SUBWINDOW); g_timeout_add (20, (GSourceFunc) iris_callback, data); num_iris_timeouts++; } /* FIXME: * Hackaround for Pango opening a separate display * connection and doing a server grab while we have a grab * on the primary display connection. This forces Pango * to go ahead and do its font cache before we try to * grab the server. * * c/f metacity/src/ui.c:meta_ui_init() */ static void force_pango_cache_init (void) { PangoFontMetrics *metrics; PangoLanguage *lang; PangoContext *context; PangoFontDescription *font_desc; context = gdk_pango_context_get (); lang = gtk_get_default_language (); font_desc = pango_font_description_from_string ("Sans 12"); metrics = pango_context_get_metrics (context, font_desc, lang); pango_font_metrics_unref (metrics); pango_font_description_free (font_desc); } void run_logout_dialog (void) { GladeXML *xml; GtkWidget *dialog; GdkScreen *screen; GtkWidget *invisible; gint i; gboolean a11y_enabled; msm_verbose ("run_logout_dialog\n"); xml = glade_xml_new ("logout-dialog.glade", NULL, NULL); dialog = glade_xml_get_widget (xml, "logout_dialog"); /* FIXME: Find the right screen for multi-head */ screen = gdk_screen_get_default (); invisible = gtk_invisible_new_for_screen (screen); i = 0; #if 0 while (0) { if (gdk_pointer_grab (invisible->window, FALSE, 0, NULL, NULL, GDK_CURRENT_TIME) == Success) { if (gdk_keyboard_grab (invisible->window, FALSE, GDK_CURRENT_TIME) == Success) break; gdk_pointer_ungrab (GDK_CURRENT_TIME); } sleep (1); if (i++ == 3) { /* FIXME: Do something else here */ msm_verbose ("unable to grab the keyboard. Continuing without a grab"); break; } } #endif force_pango_cache_init (); a11y_enabled = GTK_IS_ACCESSIBLE (gtk_widget_get_accessible (invisible)); /* Grabbing the Xserver when accessibility is enabled will cause * a hang. See #93103 for details. */ if (!a11y_enabled) { // XGrabServer (GDK_DISPLAY ()); msm_screen_foreach (run_logout_effect); } gtk_main(); g_print ("result: %d\n", gtk_dialog_run (GTK_DIALOG (dialog))); } int main (int argc, char *argv[]) { gtk_init (&argc, &argv); run_logout_dialog (); return 0; }