]> git.eshelyaron.com Git - emacs.git/commitdiff
Implement font selection dialog on Haiku
authorPo Lu <luangruo@yahoo.com>
Sun, 1 May 2022 00:59:55 +0000 (00:59 +0000)
committerPo Lu <luangruo@yahoo.com>
Sun, 1 May 2022 01:00:15 +0000 (01:00 +0000)
* src/haiku_font_support.cc (font_style_to_flags): Handle style
allocation failures.
(be_font_style_to_flags): New function.

* src/haiku_support.cc (struct font_selection_dialog_message):
New struct.
(class EmacsFontSelectionDialog): New class.
(be_select_font): New function.

* src/haiku_support.h: Update prototypes.
* src/haikufont.c (Fx_select_font): New function.
(syms_of_haikufont): Define new subr.

src/haiku_font_support.cc
src/haiku_support.cc
src/haiku_support.h
src/haikufont.c

index 9acdd652e349d483287bc1d2f2b9183f02f674b7..95a0db8ae689cbb1013bce35020ae21d752bb29b 100644 (file)
@@ -294,6 +294,9 @@ font_style_to_flags (char *st, struct haiku_font_pattern *pattern)
   char *token;
   int tok = 0;
 
+  if (!style)
+    return;
+
   pattern->weight = NO_WEIGHT;
   pattern->width = NO_WIDTH;
   pattern->slant = NO_SLANT;
@@ -804,3 +807,11 @@ be_evict_font_cache (void)
       font_object_cache[i] = NULL;
     }
 }
+
+void
+be_font_style_to_flags (char *style, struct haiku_font_pattern *pattern)
+{
+  pattern->specified = 0;
+
+  font_style_to_flags (style, pattern);
+}
index 8ad3c58a17e21a7078890e2d3cfd50c1b2b319e8..32b05a499df4b5e27a6f5aee809d96fb978fa5b1 100644 (file)
@@ -38,6 +38,9 @@ along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
 #include <interface/Button.h>
 #include <interface/ControlLook.h>
 #include <interface/Deskbar.h>
+#include <interface/ListView.h>
+#include <interface/StringItem.h>
+#include <interface/SplitView.h>
 
 #include <locale/UnicodeChar.h>
 
@@ -54,6 +57,7 @@ along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
 #include <support/Beep.h>
 #include <support/DataIO.h>
 #include <support/Locker.h>
+#include <support/ObjectList.h>
 
 #include <translation/TranslatorRoster.h>
 #include <translation/TranslationDefs.h>
@@ -84,14 +88,16 @@ along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
 /* Some messages that Emacs sends to itself.  */
 enum
   {
-    SCROLL_BAR_UPDATE  = 3000,
-    WAIT_FOR_RELEASE   = 3001,
-    RELEASE_NOW                = 3002,
-    CANCEL_DROP                = 3003,
-    SHOW_MENU_BAR      = 3004,
-    BE_MENU_BAR_OPEN   = 3005,
-    QUIT_APPLICATION   = 3006,
-    REPLAY_MENU_BAR    = 3007,
+    SCROLL_BAR_UPDATE   = 3000,
+    WAIT_FOR_RELEASE    = 3001,
+    RELEASE_NOW                 = 3002,
+    CANCEL_DROP                 = 3003,
+    SHOW_MENU_BAR       = 3004,
+    BE_MENU_BAR_OPEN    = 3005,
+    QUIT_APPLICATION    = 3006,
+    REPLAY_MENU_BAR     = 3007,
+    FONT_FAMILY_SELECTED = 3008,
+    FONT_STYLE_SELECTED         = 3009,
   };
 
 /* X11 keysyms that we use.  */
@@ -122,6 +128,18 @@ enum
     KEY_ZENKAKU_HANKAKU          = 0xff2a,
   };
 
+struct font_selection_dialog_message
+{
+  /* Whether or not font selection was cancelled.  */
+  bool cancel;
+
+  /* The index of the selected font family.  */
+  int family_idx;
+
+  /* The index of the selected font style.  */
+  int style_idx;
+};
+
 static color_space dpy_color_space = B_NO_COLOR_SPACE;
 static key_map *key_map = NULL;
 static char *key_chars = NULL;
@@ -2408,6 +2426,243 @@ public:
   }
 };
 
+class EmacsFontSelectionDialog : public BWindow
+{
+  BSplitView split_view;
+  BListView font_family_pane;
+  BListView font_style_pane;
+  BObjectList<BStringItem> all_families;
+  BObjectList<BStringItem> all_styles;
+  BButton cancel_button, ok_button;
+  port_id comm_port;
+
+  void
+  UpdateStylesForIndex (int idx)
+  {
+    int n, i;
+    uint32 flags;
+    font_family family;
+    font_style style;
+    BStringItem *item;
+
+    n = all_styles.CountItems ();
+
+    font_style_pane.MakeEmpty ();
+    all_styles.MakeEmpty ();
+
+    if (get_font_family (idx, &family, &flags) == B_OK)
+      {
+       n = count_font_styles (family);
+
+       for (i = 0; i < n; ++i)
+         {
+           if (get_font_style (family, i, &style, &flags) == B_OK)
+             item = new BStringItem (style);
+           else
+             item = new BStringItem ("<error>");
+
+           font_style_pane.AddItem (item);
+           all_styles.AddItem (item);
+         }
+      }
+
+    UpdateForSelectedStyle ();
+  }
+
+  bool
+  QuitRequested (void)
+  {
+    struct font_selection_dialog_message rq;
+
+    rq.cancel = true;
+    write_port (comm_port, 0, &rq, sizeof rq);
+
+    return false;
+  }
+
+  void
+  UpdateForSelectedStyle (void)
+  {
+    if (font_style_pane.CurrentSelection () < 0)
+      ok_button.SetEnabled (false);
+    else
+      ok_button.SetEnabled (true);
+  }
+
+  void
+  MessageReceived (BMessage *msg)
+  {
+    int idx;
+    struct font_selection_dialog_message rq;
+
+    if (msg->what == FONT_FAMILY_SELECTED)
+      {
+       idx = font_family_pane.CurrentSelection ();
+       UpdateStylesForIndex (idx);
+      }
+    else if (msg->what == FONT_STYLE_SELECTED)
+      UpdateForSelectedStyle ();
+    else if (msg->what == B_OK)
+      {
+       rq.cancel = false;
+       rq.family_idx = font_family_pane.CurrentSelection ();
+       rq.style_idx = font_style_pane.CurrentSelection ();
+
+       write_port (comm_port, 0, &rq, sizeof rq);
+      }
+    else if (msg->what == B_CANCEL)
+      {
+       rq.cancel = true;
+
+       write_port (comm_port, 0, &rq, sizeof rq);
+      }
+
+    BWindow::MessageReceived (msg);
+  }
+
+public:
+
+  ~EmacsFontSelectionDialog (void)
+  {
+    font_family_pane.MakeEmpty ();
+    font_style_pane.MakeEmpty ();
+
+    split_view.RemoveSelf ();
+    cancel_button.RemoveSelf ();
+    ok_button.RemoveSelf ();
+
+    if (comm_port >= B_OK)
+      delete_port (comm_port);
+  }
+
+  EmacsFontSelectionDialog (void) : BWindow (BRect (0, 0, 300, 300), "",
+                                            B_TITLED_WINDOW_LOOK,
+                                            B_NORMAL_WINDOW_FEEL, 0),
+                                   all_families (20, true),
+                                   all_styles (20, true),
+                                   cancel_button ("Cancel", "Cancel",
+                                                  new BMessage (B_CANCEL)),
+                                   ok_button ("OK", "OK", new BMessage (B_OK))
+  {
+    BStringItem *family_item;
+    int i, n_families;
+    font_family name;
+    uint32 flags;
+    BMessage *selection;
+
+    AddChild (&split_view);
+    AddChild (&cancel_button);
+    AddChild (&ok_button);
+    split_view.AddChild (&font_family_pane);
+    split_view.AddChild (&font_style_pane);
+
+    FrameResized (801, 801);
+    UpdateForSelectedStyle ();
+
+    selection = new BMessage (FONT_FAMILY_SELECTED);
+    font_family_pane.SetSelectionMessage (selection);
+    selection = new BMessage (FONT_STYLE_SELECTED);
+    font_style_pane.SetSelectionMessage (selection);
+
+    comm_port = create_port (1, "font dialog port");
+
+    n_families = count_font_families ();
+
+    for (i = 0; i < n_families; ++i)
+      {
+       if (get_font_family (i, &name, &flags) == B_OK)
+         {
+           family_item = new BStringItem (name);
+
+           all_families.AddItem (family_item);
+           font_family_pane.AddItem (family_item);
+         }
+       else
+         {
+           family_item = new BStringItem ("<error>");
+
+           all_families.AddItem (family_item);
+           font_family_pane.AddItem (family_item);
+         }
+      }
+  }
+
+  void
+  FrameResized (float new_width, float new_height)
+  {
+    BRect frame = Frame ();
+    float ok_height, ok_width;
+    float cancel_height, cancel_width;
+    int max_height;
+
+    ok_button.GetPreferredSize (&ok_width, &ok_height);
+    cancel_button.GetPreferredSize (&cancel_width,
+                                   &cancel_height);
+
+    max_height = std::max (ok_height, cancel_height);
+
+    split_view.ResizeTo (BE_RECT_WIDTH (frame),
+                        BE_RECT_HEIGHT (frame) - 4 - max_height);
+    ok_button.MoveTo ((BE_RECT_WIDTH (frame)
+                      - 4 - cancel_width - ok_width),
+                     BE_RECT_HEIGHT (frame) - 2 - max_height);
+    cancel_button.MoveTo (BE_RECT_WIDTH (frame) - 2 - cancel_width,
+                         BE_RECT_HEIGHT (frame) - 2 - max_height);
+    ok_button.ResizeTo (ok_width, ok_height);
+    cancel_button.ResizeTo (cancel_width, cancel_height);
+  }
+
+  void
+  WaitForChoice (struct font_selection_dialog_message *msg,
+                void (*process_pending_signals_function) (void))
+  {
+    int32 reply_type;
+    struct object_wait_info infos[2];
+    ssize_t status;
+
+    infos[0].object = port_application_to_emacs;
+    infos[0].type = B_OBJECT_TYPE_PORT;
+    infos[0].events = B_EVENT_READ;
+
+    infos[1].object = comm_port;
+    infos[1].type = B_OBJECT_TYPE_PORT;
+    infos[1].events = B_EVENT_READ;
+
+    while (true)
+      {
+       status = wait_for_objects (infos, 2);
+
+       if (status < B_OK)
+         continue;
+
+       if (infos[1].events & B_EVENT_READ)
+         {
+           if (read_port (comm_port, &reply_type,
+                          msg, sizeof *msg) >= B_OK)
+             return;
+
+           goto cancel;
+         }
+
+       if (infos[0].events & B_EVENT_READ)
+         process_pending_signals_function ();
+
+       infos[0].events = B_EVENT_READ;
+       infos[1].events = B_EVENT_READ;
+      }
+
+  cancel:
+    msg->cancel = true;
+    return;
+  }
+
+  status_t
+  InitCheck (void)
+  {
+    return comm_port >= B_OK ? B_OK : comm_port;
+  }
+};
+
 static int32
 start_running_application (void *data)
 {
@@ -4370,3 +4625,45 @@ be_get_ui_color (const char *name, uint32_t *color)
 
   return 0;
 }
+
+bool
+be_select_font (void (*process_pending_signals_function) (void),
+               haiku_font_family_or_style *family,
+               haiku_font_family_or_style *style)
+{
+  EmacsFontSelectionDialog *dialog;
+  struct font_selection_dialog_message msg;
+  uint32 flags;
+  font_family family_buffer;
+  font_style style_buffer;
+
+  dialog = new EmacsFontSelectionDialog;
+  dialog->CenterOnScreen ();
+
+  if (dialog->InitCheck () < B_OK)
+    {
+      dialog->Quit ();
+      return false;
+    }
+
+  dialog->Show ();
+  dialog->WaitForChoice (&msg, process_pending_signals_function);
+
+  if (!dialog->LockLooper ())
+    gui_abort ("Failed to lock font selection dialog looper");
+  dialog->Quit ();
+
+  if (msg.cancel)
+    return false;
+
+  if (get_font_family (msg.family_idx,
+                      &family_buffer, &flags) != B_OK
+      || get_font_style (family_buffer, msg.style_idx,
+                        &style_buffer, &flags) != B_OK)
+    return false;
+
+  memcpy (family, family_buffer, sizeof *family);
+  memcpy (style, style_buffer, sizeof *style);
+
+  return true;
+}
index 88edc1ae1499793f8dacfa3bb96a1d03b2dc938a..faaee2ed9de163b4c88c0ac5a106671e91835584 100644 (file)
@@ -648,6 +648,7 @@ extern int be_get_display_screens (void);
 extern bool be_use_subpixel_antialiasing (void);
 extern const char *be_find_setting (const char *);
 extern haiku_font_family_or_style *be_list_font_families (size_t *);
+extern void be_font_style_to_flags (char *, struct haiku_font_pattern *);
 extern int be_get_ui_color (const char *, uint32_t *);
 
 extern void BMessage_delete (void *);
@@ -658,6 +659,9 @@ extern bool be_drag_message (void *, void *, bool, void (*) (void),
 extern bool be_drag_and_drop_in_progress (void);
 
 extern bool be_replay_menu_bar_event (void *, struct haiku_menu_bar_click_event *);
+extern bool be_select_font (void (*process_pending_signals_function) (void),
+                           haiku_font_family_or_style *,
+                           haiku_font_family_or_style *);
 #ifdef __cplusplus
 }
 
index 7dd23fba7aadc3cee6e78bc9df39918821b12e71..bca29c4ed3872901ffb803aeafc6109a732cfb19 100644 (file)
@@ -1082,6 +1082,53 @@ struct font_driver const haikufont_driver =
     .list_family = haikufont_list_family
   };
 
+DEFUN ("x-select-font", Fx_select_font, Sx_select_font, 0, 2, 0,
+       doc: /* Read a font using a native dialog.
+Return a font spec describing the font chosen by the user.
+
+FRAME is the frame on which to pop up the font chooser.  If omitted or
+nil, it defaults to the selected frame.
+If EXCLUDE-PROPORTIONAL is non-nil, exclude proportional fonts
+in the font selection dialog.  */)
+  (Lisp_Object frame, Lisp_Object exclude_proportional)
+{
+  haiku_font_family_or_style family, style;
+  bool rc;
+  struct haiku_font_pattern pattern;
+  Lisp_Object lfamily, lweight, lslant, lwidth, ladstyle;
+
+  decode_window_system_frame (frame);
+
+  if (popup_activated_p)
+    error ("Trying to use a menu from within a menu-entry");
+
+  popup_activated_p++;
+  rc = be_select_font (process_pending_signals, &family, &style);
+  popup_activated_p--;
+
+  if (!rc)
+    quit ();
+
+  be_font_style_to_flags (style, &pattern);
+
+  lfamily = build_string_from_utf8 (family);
+  lweight = (pattern.specified & FSPEC_WEIGHT
+            ? haikufont_weight_to_lisp (pattern.weight)
+            : Qunspecified);
+  lslant = (pattern.specified & FSPEC_SLANT
+           ? haikufont_slant_to_lisp (pattern.slant)
+           : Qunspecified);
+  lwidth = (pattern.specified & FSPEC_WIDTH
+           ? haikufont_width_to_lisp (pattern.width)
+           : Qunspecified);
+  ladstyle = (pattern.specified & FSPEC_STYLE
+            ? intern (pattern.style) : Qunspecified);
+
+  return CALLN (Ffont_spec, QCfamily, lfamily,
+               QCweight, lweight, QCslant, lslant,
+               QCwidth, lwidth, QCadstyle, ladstyle);
+}
+
 void
 syms_of_haikufont (void)
 {
@@ -1112,5 +1159,7 @@ syms_of_haikufont (void)
   font_cache = list (Qnil);
   staticpro (&font_cache);
 
+  defsubr (&Sx_select_font);
+
   be_init_font_data ();
 }