summaryrefslogtreecommitdiffstats
path: root/gnome-session/gsm-fail-whale-dialog.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 17:49:37 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 17:49:37 +0000
commit35504d91654321ff2b378229ff13150f53d5aad2 (patch)
treecb85edefc751b37c8423d78c5e5888f42cc01e4b /gnome-session/gsm-fail-whale-dialog.c
parentInitial commit. (diff)
downloadgnome-session-35504d91654321ff2b378229ff13150f53d5aad2.tar.xz
gnome-session-35504d91654321ff2b378229ff13150f53d5aad2.zip
Adding upstream version 43.0.upstream/43.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'gnome-session/gsm-fail-whale-dialog.c')
-rw-r--r--gnome-session/gsm-fail-whale-dialog.c461
1 files changed, 461 insertions, 0 deletions
diff --git a/gnome-session/gsm-fail-whale-dialog.c b/gnome-session/gsm-fail-whale-dialog.c
new file mode 100644
index 0000000..d6e8407
--- /dev/null
+++ b/gnome-session/gsm-fail-whale-dialog.c
@@ -0,0 +1,461 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2011 Red Hat, Inc.
+ * Copyright (C) 2019 Canonical Ltd.
+ *
+ * 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 2 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/>.
+ *
+ * Authors:
+ * Colin Walters <walters@verbum.org>
+ * Marco Trevisan <marco@ubuntu.com>
+ */
+
+#include <config.h>
+
+#include <stdlib.h>
+
+#include <glib/gi18n.h>
+
+#include <gtk/gtk.h>
+#ifdef GDK_WINDOWING_X11
+#include <gtk/gtkx.h>
+#endif
+
+#include "gsm-fail-whale-dialog.h"
+
+#include "gsm-icon-names.h"
+
+struct _GsmFailWhaleDialog
+{
+ GtkWindow parent;
+
+ gboolean debug_mode;
+ gboolean allow_logout;
+ gboolean extensions;
+ GdkMonitor *monitor;
+ GdkRectangle geometry;
+};
+
+G_DEFINE_TYPE (GsmFailWhaleDialog, gsm_fail_whale_dialog, GTK_TYPE_WINDOW);
+
+/* derived from tomboy */
+static void
+_window_override_user_time (GsmFailWhaleDialog *window)
+{
+ guint32 ev_time = gtk_get_current_event_time ();
+ GdkWindow *gdk_window = gtk_widget_get_window (GTK_WIDGET (window));
+
+#ifdef GDK_WINDOWING_X11
+ if (!GDK_IS_X11_WINDOW (gdk_window))
+ return;
+
+ if (ev_time == 0) {
+ gint ev_mask = gtk_widget_get_events (GTK_WIDGET (window));
+ if (!(ev_mask & GDK_PROPERTY_CHANGE_MASK)) {
+ gtk_widget_add_events (GTK_WIDGET (window),
+ GDK_PROPERTY_CHANGE_MASK);
+ }
+
+ /*
+ * NOTE: Last resort for D-BUS or other non-interactive
+ * openings. Causes roundtrip to server. Lame.
+ */
+ ev_time = gdk_x11_get_server_time (gdk_window);
+ }
+
+ gdk_x11_window_set_user_time (gdk_window, ev_time);
+#endif
+}
+
+static void
+_window_move_resize_window (GsmFailWhaleDialog *window,
+ gboolean move,
+ gboolean resize)
+{
+ if (window->debug_mode)
+ return;
+
+ g_debug ("Move and/or resize window x=%d y=%d w=%d h=%d",
+ window->geometry.x,
+ window->geometry.y,
+ window->geometry.width,
+ window->geometry.height);
+
+ if (resize) {
+ gtk_window_resize (GTK_WINDOW (window),
+ window->geometry.width,
+ window->geometry.height);
+ }
+
+ if (move) {
+ gtk_window_move (GTK_WINDOW (window),
+ window->geometry.x,
+ window->geometry.y);
+ }
+}
+
+static void
+update_geometry (GsmFailWhaleDialog *fail_dialog)
+{
+ gdk_monitor_get_geometry (fail_dialog->monitor, &fail_dialog->geometry);
+}
+
+static void
+on_screen_size_changed (GdkScreen *screen,
+ GsmFailWhaleDialog *fail_dialog)
+{
+ gtk_widget_queue_resize (GTK_WIDGET (fail_dialog));
+}
+
+static void
+gsm_fail_whale_dialog_realize (GtkWidget *widget)
+{
+ if (GTK_WIDGET_CLASS (gsm_fail_whale_dialog_parent_class)->realize) {
+ GTK_WIDGET_CLASS (gsm_fail_whale_dialog_parent_class)->realize (widget);
+ }
+
+ _window_override_user_time (GSM_FAIL_WHALE_DIALOG (widget));
+ update_geometry (GSM_FAIL_WHALE_DIALOG (widget));
+ _window_move_resize_window (GSM_FAIL_WHALE_DIALOG (widget), TRUE, TRUE);
+
+ g_signal_connect (gtk_window_get_screen (GTK_WINDOW (widget)),
+ "size_changed",
+ G_CALLBACK (on_screen_size_changed),
+ widget);
+}
+
+static void
+gsm_fail_whale_dialog_unrealize (GtkWidget *widget)
+{
+ g_signal_handlers_disconnect_by_func (gtk_window_get_screen (GTK_WINDOW (widget)),
+ on_screen_size_changed,
+ widget);
+
+ if (GTK_WIDGET_CLASS (gsm_fail_whale_dialog_parent_class)->unrealize) {
+ GTK_WIDGET_CLASS (gsm_fail_whale_dialog_parent_class)->unrealize (widget);
+ }
+}
+
+static void
+gsm_fail_whale_dialog_size_request (GtkWidget *widget,
+ GtkRequisition *requisition)
+{
+ GsmFailWhaleDialog *fail_dialog;
+ GdkRectangle old_geometry;
+ int position_changed = FALSE;
+ int size_changed = FALSE;
+
+ fail_dialog = GSM_FAIL_WHALE_DIALOG (widget);
+
+ old_geometry = fail_dialog->geometry;
+
+ update_geometry (fail_dialog);
+
+ requisition->width = fail_dialog->geometry.width;
+ requisition->height = fail_dialog->geometry.height;
+
+ if (!gtk_widget_get_realized (widget)) {
+ return;
+ }
+
+ if (old_geometry.width != fail_dialog->geometry.width ||
+ old_geometry.height != fail_dialog->geometry.height) {
+ size_changed = TRUE;
+ }
+
+ if (old_geometry.x != fail_dialog->geometry.x ||
+ old_geometry.y != fail_dialog->geometry.y) {
+ position_changed = TRUE;
+ }
+
+ _window_move_resize_window (fail_dialog,
+ position_changed, size_changed);
+}
+
+static void
+gsm_fail_whale_dialog_get_preferred_width (GtkWidget *widget,
+ gint *minimal_width,
+ gint *natural_width)
+{
+ GtkRequisition requisition;
+
+ gsm_fail_whale_dialog_size_request (widget, &requisition);
+
+ *minimal_width = *natural_width = requisition.width;
+}
+
+static void
+gsm_fail_whale_dialog_get_preferred_width_for_height (GtkWidget *widget,
+ gint for_height,
+ gint *minimal_width,
+ gint *natural_width)
+{
+ GtkRequisition requisition;
+
+ gsm_fail_whale_dialog_size_request (widget, &requisition);
+
+ *minimal_width = *natural_width = requisition.width;
+}
+
+static void
+gsm_fail_whale_dialog_get_preferred_height (GtkWidget *widget,
+ gint *minimal_height,
+ gint *natural_height)
+{
+ GtkRequisition requisition;
+
+ gsm_fail_whale_dialog_size_request (widget, &requisition);
+
+ *minimal_height = *natural_height = requisition.height;
+}
+
+static void
+gsm_fail_whale_dialog_get_preferred_height_for_width (GtkWidget *widget,
+ gint for_width,
+ gint *minimal_height,
+ gint *natural_height)
+{
+ GtkRequisition requisition;
+
+ gsm_fail_whale_dialog_size_request (widget, &requisition);
+
+ *minimal_height = *natural_height = requisition.height;
+}
+
+static void
+gsm_fail_whale_dialog_class_init (GsmFailWhaleDialogClass *klass)
+{
+ GtkWidgetClass *widget_class;
+
+ widget_class = GTK_WIDGET_CLASS (klass);
+
+ widget_class->realize = gsm_fail_whale_dialog_realize;
+ widget_class->unrealize = gsm_fail_whale_dialog_unrealize;
+ widget_class->get_preferred_width = gsm_fail_whale_dialog_get_preferred_width;
+ widget_class->get_preferred_height = gsm_fail_whale_dialog_get_preferred_height;
+ widget_class->get_preferred_width_for_height = gsm_fail_whale_dialog_get_preferred_width_for_height;
+ widget_class->get_preferred_height_for_width = gsm_fail_whale_dialog_get_preferred_height_for_width;
+}
+
+static void
+on_logout_clicked (GtkWidget *button,
+ GsmFailWhaleDialog *fail_dialog)
+{
+ if (!fail_dialog->debug_mode) {
+ g_spawn_command_line_async ("gnome-session-quit --force", NULL);
+ }
+ gtk_main_quit ();
+}
+
+static void
+setup_window (GsmFailWhaleDialog *fail_dialog)
+{
+ GtkWidget *box;
+ GtkWidget *image;
+ GtkWidget *label;
+ GtkWidget *message_label;
+ GtkWidget *button_box;
+ GtkWidget *button;
+ GdkPixbuf *fail_icon;
+ GdkDisplay *display;
+ char *markup;
+ int scale_factor;
+ int i;
+
+ gtk_window_set_title (GTK_WINDOW (fail_dialog), "");
+ gtk_window_set_icon_name (GTK_WINDOW (fail_dialog), GSM_ICON_COMPUTER_FAIL);
+
+ gtk_window_set_skip_taskbar_hint (GTK_WINDOW (fail_dialog), TRUE);
+ gtk_window_set_keep_above (GTK_WINDOW (fail_dialog), TRUE);
+ gtk_window_stick (GTK_WINDOW (fail_dialog));
+ gtk_window_set_position (GTK_WINDOW (fail_dialog), GTK_WIN_POS_CENTER_ALWAYS);
+
+ /* only works if there is a window manager which is unlikely */
+ display = gtk_widget_get_display (GTK_WIDGET (fail_dialog));
+ for (i = 0; i < gdk_display_get_n_monitors (display); i++) {
+ if (gdk_display_get_monitor (display, i) == fail_dialog->monitor) {
+ GdkScreen *screen;
+
+ screen = gtk_widget_get_screen (GTK_WIDGET (fail_dialog));
+ gtk_window_fullscreen_on_monitor (GTK_WINDOW (fail_dialog),
+ screen, i);
+ break;
+ }
+ }
+
+ box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 10);
+ gtk_widget_set_valign (box, GTK_ALIGN_CENTER);
+ gtk_widget_show (box);
+
+ gtk_container_add (GTK_CONTAINER (fail_dialog), box);
+
+ scale_factor = gdk_monitor_get_scale_factor (fail_dialog->monitor);
+ fail_icon = gtk_icon_theme_load_icon_for_scale (gtk_icon_theme_get_default (),
+ GSM_ICON_COMPUTER_FAIL,
+ 128,
+ scale_factor,
+ 0,
+ NULL);
+ if (fail_icon != NULL) {
+ image = gtk_image_new_from_pixbuf (fail_icon);
+ gtk_widget_show (image);
+ gtk_box_pack_start (GTK_BOX (box), image, FALSE, FALSE, 0);
+ g_object_unref (fail_icon);
+ }
+
+ label = gtk_label_new (NULL);
+ markup = g_strdup_printf ("<b><big>%s</big></b>", _("Oh no! Something has gone wrong."));
+ gtk_label_set_markup (GTK_LABEL (label), markup);
+ g_free (markup);
+ gtk_widget_show (label);
+ gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0);
+
+ if (!fail_dialog->allow_logout)
+ message_label = gtk_label_new (_("A problem has occurred and the system can’t recover. Please contact a system administrator"));
+ else if (fail_dialog->extensions)
+ message_label = gtk_label_new (_("A problem has occurred and the system can’t recover. All extensions have been disabled as a precaution."));
+ else
+ message_label = gtk_label_new (_("A problem has occurred and the system can’t recover.\nPlease log out and try again."));
+
+ gtk_label_set_justify (GTK_LABEL (message_label), GTK_JUSTIFY_CENTER);
+ gtk_label_set_line_wrap (GTK_LABEL (message_label), TRUE);
+ gtk_widget_show (message_label);
+ gtk_box_pack_start (GTK_BOX (box),
+ message_label, FALSE, FALSE, 0);
+
+ button_box = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL);
+ gtk_container_set_border_width (GTK_CONTAINER (button_box), 20);
+ gtk_widget_show (button_box);
+ gtk_box_pack_end (GTK_BOX (box),
+ button_box, FALSE, FALSE, 0);
+
+ if (fail_dialog->allow_logout) {
+ button = gtk_button_new_with_mnemonic (_("_Log Out"));
+ gtk_widget_show (button);
+ gtk_box_pack_end (GTK_BOX (button_box),
+ button, FALSE, FALSE, 0);
+ g_signal_connect (button, "clicked",
+ G_CALLBACK (on_logout_clicked), fail_dialog);
+ }
+}
+
+static void
+gsm_fail_whale_dialog_init (GsmFailWhaleDialog *fail_dialog)
+{
+}
+
+static gboolean debug_mode = FALSE;
+static gboolean allow_logout = FALSE;
+static gboolean extensions = FALSE;
+static GList *dialogs = NULL;
+
+static void
+create_fail_dialog (GdkMonitor *monitor)
+{
+ GsmFailWhaleDialog *fail_dialog;
+
+ fail_dialog = g_object_new (GSM_TYPE_FAIL_WHALE_DIALOG, NULL);
+ fail_dialog->debug_mode = debug_mode;
+ fail_dialog->allow_logout = allow_logout;
+ fail_dialog->extensions = extensions;
+ fail_dialog->monitor = monitor;
+
+ setup_window (fail_dialog);
+
+ g_signal_connect (fail_dialog, "destroy",
+ G_CALLBACK (gtk_main_quit), NULL);
+
+ gtk_widget_show (GTK_WIDGET (fail_dialog));
+
+ dialogs = g_list_prepend (dialogs, fail_dialog);
+}
+
+static void
+on_monitor_added (GdkDisplay *display,
+ GdkMonitor *monitor)
+{
+ create_fail_dialog (monitor);
+}
+
+static void
+on_monitor_removed (GdkDisplay *display,
+ GdkMonitor *monitor)
+{
+ GList *l;
+
+ for (l = dialogs; l;) {
+ GList *next = l->next;
+ GsmFailWhaleDialog *fail_dialog = l->data;
+
+ if (fail_dialog->monitor == monitor) {
+ dialogs = g_list_delete_link (dialogs, l);
+ gtk_widget_destroy (GTK_WIDGET (fail_dialog));
+ }
+ l = next;
+ }
+}
+
+int main (int argc, char *argv[])
+{
+ GOptionEntry entries[] = {
+ { "debug", 0, 0, G_OPTION_ARG_NONE, &debug_mode, N_("Enable debugging code"), NULL },
+ { "allow-logout", 0, 0, G_OPTION_ARG_NONE, &allow_logout, N_("Allow logout"), NULL },
+ { "extensions", 0, 0, G_OPTION_ARG_NONE, &extensions, N_("Show extension warning"), NULL },
+ { NULL, 0, 0, 0, NULL, NULL, NULL }
+ };
+
+ GError *error = NULL;
+ GdkDisplay *display;
+ int i;
+
+ bindtextdomain (GETTEXT_PACKAGE, LOCALE_DIR);
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+ textdomain (GETTEXT_PACKAGE);
+
+ if (!gtk_init_with_args (&argc, &argv, " - fail whale",
+ entries, GETTEXT_PACKAGE,
+ &error)) {
+ if (error != NULL) {
+ g_warning ("%s", error->message);
+ exit (1);
+ }
+
+ /* display server probably went away. Could be for legitimate reasons, could be for
+ * unexpected reasons. If it went away unexpectantly, that's logged elsewhere, so
+ * let's not add noise by logging here.
+ */
+ return 0;
+ }
+
+ /* Force-off allow_logout when running inside GDM, this is needed
+ * because the systemd service always passes --allow-logout
+ */
+ if (g_strcmp0 (g_getenv ("RUNNING_UNDER_GDM"), "true") == 0)
+ allow_logout = FALSE;
+
+ display = gdk_display_get_default ();
+ for (i = 0; i < gdk_display_get_n_monitors (display); i++) {
+ create_fail_dialog (gdk_display_get_monitor (display, i));
+ }
+
+ g_signal_connect (display, "monitor-added",
+ G_CALLBACK (on_monitor_added), &dialogs);
+ g_signal_connect (display, "monitor-removed",
+ G_CALLBACK (on_monitor_removed), &dialogs);
+
+ gtk_main ();
+
+ return 0;
+}
+