unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* [PATCH] Change the look of dialogs created with `x-popup-dialog'
@ 2011-12-11 15:01 Andrey Smirnov
  2011-12-11 15:29 ` Lennart Borgman
                   ` (2 more replies)
  0 siblings, 3 replies; 12+ messages in thread
From: Andrey Smirnov @ 2011-12-11 15:01 UTC (permalink / raw)
  To: emacs-devel

[-- Attachment #1: Type: text/plain, Size: 1191 bytes --]

Hello everybody,

I often close emacs with mouse by pressing 'close' buttons of its
window and therefore I often encounter questions presented in form of
dialogs produced by `x-popup-dialog' function. I know it is the matter
of one's taste, but I think that appearance of aforementioned dialogs
could be improved by making them look more similar to those created by
other Gtk and GNOME applications(I used GEdit as a template). The
patch in attachment is my attempt to implements such changes. To
summarize it does the following:

  - Adds, depending on the dialog type, appropriate icon to the dialog,
    one of GTK_STOCK_DIALOG_INFO or GTK_STOCK_DIALOG_QUESTION.
  - Removes resize button from the resulting dialog window.
  - For dialogs with more than two buttons, radio-buttons instead of
    regular buttons are created.
  - Makes the question to be rendered in bold font.

The difference between the results of `x-popup-dialog' can be seen on
the image in the attachment.

I guess, there are probably many improvements that can be added both
to the dialog's appearance and to other code of the patch, so at this
point I would like you to ask to comment on the patch.

Andrey Smirnov

[-- Attachment #2: 0001-Change-the-look-of-dialogs-created-with-x-popup-dial.patch --]
[-- Type: text/x-diff, Size: 13027 bytes --]

From 53a4634fc4ce2e72278c8d8df65148f89bd4cf0a Mon Sep 17 00:00:00 2001
From: Andrey Smirnov <andrew.smirnov@gmail.com>
Date: Sat, 10 Dec 2011 18:13:42 -0800
Subject: [PATCH 1/2] Change the look of dialogs created with
 `x-popup-dialog'(Gtk)

New code creates dialogs that looks(hopefully) more similar to dialogs
created by other Gtk applications such as GEdit. Created dialog no
longer has more than two buttons and multiple choices situation is
handled with radio-buttons.
---
 src/gtkutil.c |  255 +++++++++++++++++++++++++++++++++++++++++---------------
 src/xmenu.c   |    2 -
 2 files changed, 186 insertions(+), 71 deletions(-)

diff --git a/src/gtkutil.c b/src/gtkutil.c
index bc71685..03228a8 100644
--- a/src/gtkutil.c
+++ b/src/gtkutil.c
@@ -1398,36 +1398,38 @@ xg_set_frame_icon (FRAME_PTR f, Pixmap icon_pixmap, Pixmap icon_mask)
 /* Return the dialog title to use for a dialog of type KEY.
    This is the encoding used by lwlib.  We use the same for GTK.  */
 
-static const char *
-get_dialog_title (char key)
+static GtkWidget *
+get_dialog_icon (char key)
 {
-  const char *title = "";
+  GtkWidget *image = NULL;
 
   switch (key) {
   case 'E': case 'e':
-    title = "Error";
+    image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_ERROR,
+                                      GTK_ICON_SIZE_DIALOG);
     break;
 
   case 'I': case 'i':
-    title = "Information";
+    image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_INFO,
+                                      GTK_ICON_SIZE_DIALOG);
     break;
 
   case 'L': case 'l':
-    title = "Prompt";
     break;
 
   case 'P': case 'p':
-    title = "Prompt";
     break;
 
   case 'Q': case 'q':
-    title = "Question";
+    image = gtk_image_new_from_stock (GTK_STOCK_DIALOG_QUESTION,
+                                      GTK_ICON_SIZE_DIALOG);
     break;
   }
 
-  return title;
+  return image;
 }
 
+
 /* Callback for dialogs that get WM_DELETE_WINDOW.  We pop down
    the dialog, but return TRUE so the event does not propagate further
    in GTK.  This prevents GTK from destroying the dialog widget automatically
@@ -1458,99 +1460,214 @@ create_dialog (widget_value *wv,
                GCallback select_cb,
                GCallback deactivate_cb)
 {
-  const char *title = get_dialog_title (wv->name[0]);
   int total_buttons = wv->name[1] - '0';
-  int right_buttons = wv->name[4] - '0';
-  int left_buttons;
-  int button_nr = 0;
-  int button_spacing = 10;
+
+  /*
+     Depending on the `total_buttons' value the dialog created can be
+    of two types:
+
+    1. when total_buttons > 2, then resulting dialog has following
+    structure:
+
+    +------- content_area -------------------------+
+    | +-------- hbox ----------------------------+ |
+    | | +-------+ +-- vbox --------------------+ | |
+    | | |       | | <message>                  | | |
+    | | | image | | +------ choices_box -----+ | | |
+    | | |       | | |  o first item          | | | |
+    | | |       | | |  o second item         | | | |
+    | | |       | | |  o third item          | | | |
+    | | |       | | |  ...                   | | | |
+    | | |       | | +------------------------+ | | |
+    | | |       | | +------ bbox ------------+ | | |
+    | | |       | | |     +----+  +--------+ | | | |
+    | | |       | | |     | OK |  | Cancel | | | | |
+    | | |       | | |     +----+  +--------+ | | | |
+    | | |       | | +------------------------+ | | |
+    | | +-------+ +----------------------------+ | |
+    | +------------------------------------------+ |
+    +----------------------------------------------+
+
+    2. when total_buttons <= 2, its structure is this:
+
+    +------------- content_area ------------------------------+
+    |  +--------- hbox -------------------------------------+ |
+    |  | +---------+ +------ vbox ------------------------+ | |
+    |  | |         | | <message>                          | | |
+    |  | | image   | | +----------- choices_box --------+ | | |
+    |  | |         | | | +------------+ +-------------+ | | | |
+    |  | |         | | | | first item | | second item | | | | |
+    |  | |         | | | +------------+ +-------------+ | | | |
+    |  | |         | | +--------------------------------+ | | |
+    |  | +---------+ +------------------------------------+ | |
+    |  +----------------------------------------------------+ |
+    +---------------------------------------------------------+
+
+   */
+
   GtkWidget *wdialog = gtk_dialog_new ();
-  GtkDialog *wd = GTK_DIALOG (wdialog);
-  GtkBox *cur_box = GTK_BOX (gtk_dialog_get_action_area (wd));
+  GtkWidget *content_area = gtk_dialog_get_action_area (GTK_DIALOG (wdialog));
   widget_value *item;
-  GtkWidget *whbox_down;
 
-  /* If the number of buttons is greater than 4, make two rows of buttons
-     instead.  This looks better.  */
-  int make_two_rows = total_buttons > 4;
+  GtkWidget *hbox, *vbox, *choices_box = NULL, *w = NULL;
+  gboolean first_item_p = TRUE;
 
-  if (right_buttons == 0) right_buttons = total_buttons/2;
-  left_buttons = total_buttons - right_buttons;
+  g_object_set (wdialog,
+                "destroy-with-parent" , TRUE,
+                "modal"               , TRUE,
+                "title"               , "",
+                "name"                , "emacs-dialog",
+                "resizable"           , FALSE,
+                "skip-taskbar-hint"   , TRUE,
+                NULL);
 
-  gtk_window_set_title (GTK_WINDOW (wdialog), title);
-  gtk_widget_set_name (wdialog, "emacs-dialog");
+  hbox = gtk_hbox_new (FALSE, 12);
+  gtk_container_set_border_width (GTK_CONTAINER (hbox), 5);
 
+  vbox = gtk_vbox_new (FALSE, 12);
 
-  if (make_two_rows)
-    {
-      GtkWidget *wvbox = gtk_vbox_new (TRUE, button_spacing);
-      GtkWidget *whbox_up = gtk_hbox_new (FALSE, 0);
-      whbox_down = gtk_hbox_new (FALSE, 0);
+  {
+    GtkWidget *image = get_dialog_icon (wv->name[0]);
+    gtk_misc_set_alignment (GTK_MISC (image), 0.5, 0.0);
 
-      gtk_box_pack_start (cur_box, wvbox, FALSE, FALSE, 0);
-      gtk_box_pack_start (GTK_BOX (wvbox), whbox_up, FALSE, FALSE, 0);
-      gtk_box_pack_start (GTK_BOX (wvbox), whbox_down, FALSE, FALSE, 0);
+    gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
+  }
 
-      cur_box = GTK_BOX (whbox_up);
-    }
+  gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0);
+  gtk_container_add (GTK_CONTAINER (content_area), hbox);
 
-  g_signal_connect (G_OBJECT (wdialog), "delete-event",
-                    G_CALLBACK (dialog_delete_callback), 0);
-
-  if (deactivate_cb)
-    {
-      g_signal_connect (G_OBJECT (wdialog), "close", deactivate_cb, 0);
-      g_signal_connect (G_OBJECT (wdialog), "response", deactivate_cb, 0);
-    }
 
   for (item = wv->contents; item; item = item->next)
     {
       char *utf8_label = get_utf8_string (item->value);
-      GtkWidget *w;
-      GtkRequisition req;
 
+      /* Question */
       if (item->name && strcmp (item->name, "message") == 0)
         {
-          GtkBox *wvbox = GTK_BOX (gtk_dialog_get_content_area (wd));
-          /* This is the text part of the dialog.  */
-          w = gtk_label_new (utf8_label);
-          gtk_box_pack_start (wvbox, gtk_label_new (""), FALSE, FALSE, 0);
-          gtk_box_pack_start (wvbox, w, TRUE, TRUE, 0);
-          gtk_misc_set_alignment (GTK_MISC (w), 0.1, 0.5);
+          GtkRequisition req;
+
+          w = gtk_label_new (NULL);
+          g_object_set (w,
+                        "wrap"       , TRUE,
+                        "use-markup" , TRUE,
+                        "selectable" , TRUE,
+                        "xalign"     , 0.0,
+                        "yalign"     , 0.5,
+                        NULL);
+          {
+            gchar *message = g_strconcat
+              ("<span weight=\"bold\" size=\"larger\">",
+               utf8_label, "</span>", NULL);
+
+            gtk_label_set_markup (GTK_LABEL (w), message);
+            g_free (message);
+          }
+
+          gtk_box_pack_start (GTK_BOX (vbox), w, TRUE, TRUE, 0);
 
           /* Try to make dialog look better.  Must realize first so
              the widget can calculate the size it needs.  */
           gtk_widget_realize (w);
           gtk_widget_get_preferred_size (w, NULL, &req);
-          gtk_box_set_spacing (wvbox, req.height);
-	  if (item->value && strlen (item->value) > 0)
-            button_spacing = 2*req.width/strlen (item->value);
+          gtk_box_set_spacing (GTK_BOX (vbox), req.height);
+
+          w = NULL;
         }
+      /* Choices (radiobuttons) */
+      else if (total_buttons > 2)
+        {
+          if (!choices_box)
+            choices_box = gtk_vbox_new (TRUE, 5);
+
+          w = gtk_radio_button_new_with_label_from_widget (GTK_RADIO_BUTTON (w),
+                                               utf8_label);
+         if (!item->enabled)
+            gtk_widget_set_sensitive (w, FALSE);
+
+         if (select_cb)
+           {
+             g_signal_connect (G_OBJECT (w), "clicked",
+                               G_CALLBACK (select_cb), item->call_data);
+
+             /*
+                Since the first item of radiobutton group is selected
+                by default we have to call select_cb to set
+                `menu_item_selection' to appropriate value.
+             */
+             if (first_item_p)
+               {
+                 first_item_p = FALSE;
+                 ((void (*) (GtkWidget *, gpointer)) select_cb)
+                   (w, item->call_data);
+               }
+           }
+
+         gtk_box_pack_start (GTK_BOX (choices_box), w, TRUE, TRUE, 0);
+        }
+      /* Choices (buttons) */
       else
         {
-          /* This is one button to add to the dialog.  */
+          if (!choices_box)
+            {
+              choices_box = gtk_hbutton_box_new ();
+              gtk_button_box_set_layout (GTK_BUTTON_BOX (choices_box),
+                                         GTK_BUTTONBOX_END);
+              gtk_box_set_spacing (GTK_BOX (choices_box), 10);
+            }
+
           w = gtk_button_new_with_label (utf8_label);
-          if (! item->enabled)
-            gtk_widget_set_sensitive (w, FALSE);
+
           if (select_cb)
             g_signal_connect (G_OBJECT (w), "clicked",
                               select_cb, item->call_data);
+          if (deactivate_cb)
+            g_signal_connect (G_OBJECT (w), "clicked", deactivate_cb, NULL);
 
-          gtk_box_pack_start (cur_box, w, TRUE, TRUE, button_spacing);
-          if (++button_nr == left_buttons)
-            {
-              if (make_two_rows)
-                cur_box = GTK_BOX (whbox_down);
-              else
-                gtk_box_pack_start (cur_box,
-                                    gtk_label_new (""),
-                                    TRUE, TRUE,
-                                    button_spacing);
-            }
+
+          gtk_container_add (GTK_CONTAINER (choices_box), w);
         }
+      if (utf8_label)
+        g_free (utf8_label);
+    }
+
+  if (total_buttons > 2)
+    {
+      GtkWidget *bbox = gtk_hbutton_box_new ();
+      GtkWidget *ok = gtk_button_new_from_stock (GTK_STOCK_OK);
+      GtkWidget *cancel = gtk_button_new_from_stock (GTK_STOCK_CANCEL);
+      GtkWidget *frame  = gtk_frame_new ("Possible actions/answers");
+
+      gtk_container_add (GTK_CONTAINER (bbox), ok);
+      gtk_container_add (GTK_CONTAINER (bbox), cancel);
+
+      gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_END);
+      gtk_box_set_spacing (GTK_BOX (bbox), 10);
+
+
+      gtk_container_add (GTK_CONTAINER (frame), choices_box);
+      gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0);
+
+      gtk_box_pack_start (GTK_BOX (vbox), bbox, TRUE, TRUE, 0);
 
-     if (utf8_label)
-       g_free (utf8_label);
+      if (deactivate_cb)
+        {
+          g_signal_connect (G_OBJECT (ok), "clicked", deactivate_cb, 0);
+          g_signal_connect (G_OBJECT (cancel), "clicked", select_cb, 0);
+          g_signal_connect (G_OBJECT (cancel), "clicked", deactivate_cb, 0);
+        }
+    }
+  else
+    {
+      gtk_box_pack_start (GTK_BOX (vbox), choices_box, TRUE, TRUE, 0);
+    }
+
+  g_signal_connect (G_OBJECT (wdialog), "delete-event",
+                    G_CALLBACK (dialog_delete_callback), 0);
+
+  if (deactivate_cb)
+    {
+      g_signal_connect (G_OBJECT (wdialog), "close", deactivate_cb, 0);
+      g_signal_connect (G_OBJECT (wdialog), "response", deactivate_cb, 0);
     }
 
   return wdialog;
diff --git a/src/xmenu.c b/src/xmenu.c
index 4b7bbfd..547b538 100644
--- a/src/xmenu.c
+++ b/src/xmenu.c
@@ -1904,8 +1904,6 @@ dialog_selection_callback (GtkWidget *widget, gpointer client_data)
      as long as pointers have enough bits to hold small integers.  */
   if ((intptr_t) client_data != -1)
     menu_item_selection = (Lisp_Object *) client_data;
-
-  popup_activated_flag = 0;
 }
 
 /* Pop up the dialog for frame F defined by FIRST_WV and loop until the
-- 
1.7.5.4


[-- Attachment #3: before-after.png --]
[-- Type: image/png, Size: 86879 bytes --]

^ permalink raw reply related	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2011-12-16 17:32 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-12-11 15:01 [PATCH] Change the look of dialogs created with `x-popup-dialog' Andrey Smirnov
2011-12-11 15:29 ` Lennart Borgman
2011-12-12 17:49   ` Stefan Monnier
2011-12-13  2:47     ` Andrey Smirnov
2011-12-13  2:54       ` Lennart Borgman
2011-12-12 17:44 ` Stefan Monnier
2011-12-13  7:07 ` Jan Djärv
2011-12-14  5:29   ` Andrey Smirnov
2011-12-14 20:41     ` Jan Djärv
2011-12-15  4:56       ` Andrey Smirnov
2011-12-16 13:42         ` Jan D.
2011-12-16 17:32           ` Andrey Smirnov

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).