root/src/haiku_support.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. gui_abort
  2. be_popup_menu_thread_entry
  3. keysym_from_raw_char
  4. map_key
  5. map_shift
  6. map_caps
  7. map_caps_shift
  8. map_normal
  9. get_zoom_rect
  10. DispatchMessage
  11. settings_valid_p
  12. AboutRequested
  13. QuitRequested
  14. MessageReceived
  15. fullscreen_mode
  16. RecomputeFeel
  17. UpwardsSubset
  18. UpwardsSubsetChildren
  19. UpwardsUnSubset
  20. UpwardsUnSubsetChildren
  21. Unparent
  22. UnparentAndUnlink
  23. UnlinkChild
  24. ParentTo
  25. LinkChild
  26. MoveToIncludingFrame
  27. DoMove
  28. DoUpdateWorkspace
  29. MoveChild
  30. WindowActivated
  31. MessageReceived
  32. DispatchMessage
  33. MenusBeginning
  34. MenusEnded
  35. FrameResized
  36. FrameMoved
  37. WorkspacesChanged
  38. EmacsMoveTo
  39. QuitRequested
  40. Minimize
  41. EmacsHide
  42. EmacsShow
  43. ClearFullscreen
  44. FullscreenRectForMode
  45. SetFullscreen
  46. Zoom
  47. OffsetChildRect
  48. AttachedToWindow
  49. FrameResized
  50. MouseDown
  51. MouseMoved
  52. MessageReceived
  53. use_frame_synchronization
  54. SetFrameSynchronization
  55. MessageReceived
  56. DetachCairoSurface
  57. AttachCairoSurface
  58. TearDownDoubleBuffering
  59. AfterResize
  60. Draw
  61. FlipBuffers
  62. SetUpDoubleBuffering
  63. MouseMoved
  64. BasicMouseDown
  65. MouseDown
  66. BasicMouseUp
  67. MouseUp
  68. parent
  69. MessageReceived
  70. Pulse
  71. ValueChanged
  72. ButtonRegionFor
  73. MouseDown
  74. MouseUp
  75. MouseMoved
  76. DrawContent
  77. help
  78. DrawContent
  79. GetContentSize
  80. Highlight
  81. DoLayout
  82. QuitRequested
  83. MessageReceived
  84. current_font
  85. FrameResized
  86. MinSize
  87. view_3
  88. ShowPreview
  89. UpdatePreview
  90. HidePreview
  91. UpdateStylesForIndex
  92. QuitRequested
  93. UpdateForSelectedStyle
  94. MessageReceived
  95. preview
  96. FrameResized
  97. WaitForChoice
  98. InitCheck
  99. MessageReceived
  100. ReadFileName
  101. InitCheck
  102. AttachedToWindow
  103. start_running_application
  104. BBitmap_data
  105. BBitmap_convert
  106. BBitmap_free
  107. BBitmap_new
  108. BBitmap_dimensions
  109. wait_for_exit_of_app_thread
  110. BApplication_setup
  111. BWindow_new
  112. BWindow_quit
  113. BWindow_set_offset
  114. BWindow_dimensions
  115. BWindow_iconify
  116. BWindow_set_visible
  117. BWindow_retitle
  118. BWindow_resize
  119. BWindow_activate
  120. be_get_screen_dimensions
  121. BView_resize_to
  122. be_delete_cursor
  123. be_create_cursor_from_id
  124. BView_set_view_cursor
  125. BWindow_Flush
  126. be_make_scroll_bar_for_view
  127. BScrollBar_delete
  128. BView_move_frame
  129. BView_scroll_bar_update
  130. BScrollBar_default_size
  131. BView_invalidate
  132. BView_draw_lock
  133. BView_invalidate_region
  134. BView_draw_unlock
  135. BWindow_center_on_screen
  136. BBitmap_import_fringe_bitmap
  137. BView_publish_scroll_bar
  138. BView_forget_scroll_bar
  139. BView_inside_scroll_bar
  140. BView_get_mouse
  141. BView_convert_to_screen
  142. BView_convert_from_screen
  143. BWindow_change_decoration
  144. BWindow_set_tooltip_decoration
  145. BWindow_set_avoid_focus
  146. BView_emacs_delete
  147. BPopUpMenu_new
  148. BMenu_add_title
  149. BMenu_add_item
  150. BMenu_add_separator
  151. BMenu_new_submenu
  152. BMenu_new_menu_bar_submenu
  153. BMenu_run
  154. BPopUpMenu_delete
  155. BMenuBar_new
  156. BMenuBar_delete
  157. BMenu_delete_all
  158. BMenu_delete_from
  159. BMenu_count_items
  160. BMenu_item_at
  161. BMenu_item_set_label
  162. BMenu_item_get_menu
  163. haiku_ring_bell
  164. BAlert_new
  165. BAlert_add_button
  166. BAlert_set_offset_spacing
  167. be_alert_thread_entry
  168. BAlert_go
  169. BButton_set_enabled
  170. BView_set_tooltip
  171. be_show_sticky_tooltip
  172. BAlert_delete
  173. be_get_display_resolution
  174. EmacsWindow_parent_to
  175. EmacsWindow_unparent
  176. be_get_version_string
  177. be_get_display_planes
  178. be_get_display_color_cells
  179. be_is_display_grayscale
  180. be_warp_pointer
  181. EmacsWindow_move_weak_child
  182. find_appropriate_view_for_draw
  183. EmacsView_set_up_double_buffering
  184. EmacsView_flip_and_blit
  185. EmacsView_disable_double_buffering
  186. EmacsView_double_buffered_p
  187. be_popup_file_dialog
  188. BMenuBar_start_tracking
  189. be_can_translate_type_to_bitmap_p
  190. be_translate_bitmap_from_file_name
  191. be_translate_bitmap_from_memory
  192. BBitmap_bytes_length
  193. BView_show_tooltip
  194. EmacsView_cairo_context
  195. BView_cr_dump_clipping
  196. EmacsWindow_begin_cr_critical_section
  197. EmacsWindow_end_cr_critical_section
  198. be_string_width_with_plain_font
  199. be_plain_font_height
  200. be_get_display_screens
  201. BWindow_sync
  202. BWindow_set_size_alignment
  203. BWindow_send_behind
  204. BWindow_is_active
  205. be_use_subpixel_antialiasing
  206. BWindow_set_override_redirect
  207. be_find_setting
  208. BMessage_delete
  209. be_drag_message_thread_entry
  210. be_drag_message
  211. be_drag_and_drop_in_progress
  212. be_replay_menu_bar_event
  213. BWindow_set_z_group
  214. be_get_ui_color
  215. be_select_font
  216. BWindow_set_sticky
  217. be_roster_launch
  218. be_create_pixmap_cursor
  219. be_get_window_decorator_dimensions
  220. be_get_window_decorator_frame
  221. be_send_move_frame_event
  222. be_lock_window
  223. be_unlock_window
  224. be_set_window_fullscreen_mode
  225. be_get_explicit_workarea
  226. be_clear_grab_view
  227. be_set_use_frame_synchronization
  228. be_write_node_message
  229. be_send_message

     1 /* Haiku window system support.  Hey, Emacs, this is -*- C++ -*-
     2    Copyright (C) 2021-2023 Free Software Foundation, Inc.
     3 
     4 This file is part of GNU Emacs.
     5 
     6 GNU Emacs is free software: you can redistribute it and/or modify
     7 it under the terms of the GNU General Public License as published by
     8 the Free Software Foundation, either version 3 of the License, or (at
     9 your option) any later version.
    10 
    11 GNU Emacs is distributed in the hope that it will be useful,
    12 but WITHOUT ANY WARRANTY; without even the implied warranty of
    13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    14 GNU General Public License for more details.
    15 
    16 You should have received a copy of the GNU General Public License
    17 along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
    18 
    19 #include <config.h>
    20 #include <attribute.h>
    21 
    22 #include <app/Application.h>
    23 #include <app/Cursor.h>
    24 #include <app/Clipboard.h>
    25 #include <app/Messenger.h>
    26 #include <app/Roster.h>
    27 
    28 #include <interface/GraphicsDefs.h>
    29 #include <interface/InterfaceDefs.h>
    30 #include <interface/Bitmap.h>
    31 #include <interface/Window.h>
    32 #include <interface/View.h>
    33 #include <interface/Screen.h>
    34 #include <interface/ScrollBar.h>
    35 #include <interface/Region.h>
    36 #include <interface/Menu.h>
    37 #include <interface/MenuItem.h>
    38 #include <interface/PopUpMenu.h>
    39 #include <interface/MenuBar.h>
    40 #include <interface/Alert.h>
    41 #include <interface/Button.h>
    42 #include <interface/ControlLook.h>
    43 #include <interface/Deskbar.h>
    44 #include <interface/ListView.h>
    45 #include <interface/StringItem.h>
    46 #include <interface/SplitView.h>
    47 #include <interface/ScrollView.h>
    48 #include <interface/StringView.h>
    49 #include <interface/TextControl.h>
    50 #include <interface/CheckBox.h>
    51 
    52 #include <locale/UnicodeChar.h>
    53 
    54 #include <game/WindowScreen.h>
    55 #include <game/DirectWindow.h>
    56 
    57 #include <storage/FindDirectory.h>
    58 #include <storage/Entry.h>
    59 #include <storage/Path.h>
    60 #include <storage/FilePanel.h>
    61 #include <storage/AppFileInfo.h>
    62 #include <storage/Path.h>
    63 #include <storage/PathFinder.h>
    64 #include <storage/Node.h>
    65 
    66 #include <support/Beep.h>
    67 #include <support/DataIO.h>
    68 #include <support/Locker.h>
    69 #include <support/ObjectList.h>
    70 
    71 #include <translation/TranslatorRoster.h>
    72 #include <translation/TranslationDefs.h>
    73 #include <translation/TranslationUtils.h>
    74 
    75 #include <kernel/OS.h>
    76 #include <kernel/fs_attr.h>
    77 #include <kernel/scheduler.h>
    78 
    79 #include <private/interface/ToolTip.h>
    80 #include <private/interface/WindowPrivate.h>
    81 
    82 #include <cmath>
    83 #include <cstring>
    84 #include <cstdint>
    85 #include <cstdio>
    86 #include <csignal>
    87 #include <cfloat>
    88 
    89 #ifdef USE_BE_CAIRO
    90 #include <cairo.h>
    91 #endif
    92 
    93 #include "haiku_support.h"
    94 
    95 /* Some messages that Emacs sends to itself.  */
    96 enum
    97   {
    98     SCROLL_BAR_UPDATE        = 3000,
    99     WAIT_FOR_RELEASE         = 3001,
   100     RELEASE_NOW              = 3002,
   101     CANCEL_DROP              = 3003,
   102     SHOW_MENU_BAR            = 3004,
   103     BE_MENU_BAR_OPEN         = 3005,
   104     QUIT_APPLICATION         = 3006,
   105     REPLAY_MENU_BAR          = 3007,
   106     FONT_FAMILY_SELECTED     = 3008,
   107     FONT_STYLE_SELECTED      = 3009,
   108     FILE_PANEL_SELECTION     = 3010,
   109     QUIT_PREVIEW_DIALOG      = 3011,
   110     SET_FONT_INDICES         = 3012,
   111     SET_PREVIEW_DIALOG       = 3013,
   112     UPDATE_PREVIEW_DIALOG    = 3014,
   113     SEND_MOVE_FRAME_EVENT    = 3015,
   114     SET_DISABLE_ANTIALIASING = 3016,
   115   };
   116 
   117 /* X11 keysyms that we use.  */
   118 enum
   119   {
   120     KEY_BACKSPACE         = 0xff08,
   121     KEY_TAB               = 0xff09,
   122     KEY_RETURN            = 0xff0d,
   123     KEY_PAUSE             = 0xff13,
   124     KEY_ESCAPE            = 0xff1b,
   125     KEY_DELETE            = 0xffff,
   126     KEY_HOME              = 0xff50,
   127     KEY_LEFT_ARROW        = 0xff51,
   128     KEY_UP_ARROW          = 0xff52,
   129     KEY_RIGHT_ARROW       = 0xff53,
   130     KEY_DOWN_ARROW        = 0xff54,
   131     KEY_PAGE_UP           = 0xff55,
   132     KEY_PAGE_DOWN         = 0xff56,
   133     KEY_END               = 0xff57,
   134     KEY_PRINT             = 0xff61,
   135     KEY_INSERT            = 0xff63,
   136     /* This is used to indicate the first function key.  */
   137     KEY_F1                = 0xffbe,
   138     /* These are found on some multilingual keyboards.  */
   139     KEY_HANGUL            = 0xff31,
   140     KEY_HANGUL_HANJA      = 0xff34,
   141     KEY_HIRIGANA_KATAGANA = 0xff27,
   142     KEY_ZENKAKU_HANKAKU   = 0xff2a,
   143   };
   144 
   145 struct font_selection_dialog_message
   146 {
   147   /* Whether or not font selection was canceled.  */
   148   bool_bf cancel : 1;
   149 
   150   /* Whether or not a size was explicitly specified.  */
   151   bool_bf size_specified : 1;
   152 
   153   /* Whether or not antialiasing should be disabled.  */
   154   bool_bf disable_antialias : 1;
   155 
   156   /* The index of the selected font family.  */
   157   int family_idx;
   158 
   159   /* The index of the selected font style.  */
   160   int style_idx;
   161 
   162   /* The selected font size.  */
   163   int size;
   164 };
   165 
   166 /* The color space of the main screen.  B_NO_COLOR_SPACE means it has
   167    not yet been computed.  */
   168 static color_space dpy_color_space = B_NO_COLOR_SPACE;
   169 
   170 /* The keymap, or NULL if it has not been initialized.  */
   171 static key_map *key_map;
   172 
   173 /* Indices of characters into the keymap.  */
   174 static char *key_chars;
   175 
   176 /* Lock around keymap data, since it's touched from different
   177    threads.  */
   178 static BLocker key_map_lock;
   179 
   180 /* The locking semantics of BWindows running in multiple threads are
   181    so complex that child frame state (which is the only state that is
   182    shared between different BWindows at runtime) does best with a
   183    single global lock.  */
   184 static BLocker child_frame_lock;
   185 
   186 /* Variable where the popup menu thread returns the chosen menu
   187    item.  */
   188 static BMessage volatile *popup_track_message;
   189 
   190 /* Variable in which alert dialog threads return the selected button
   191    number.  */
   192 static int32 volatile alert_popup_value;
   193 
   194 /* The view that has the passive grab.  */
   195 static void *grab_view;
   196 
   197 /* The locker for that variable.  */
   198 static BLocker grab_view_locker;
   199 
   200 /* Whether or not a drag-and-drop operation is in progress.  */
   201 static bool drag_and_drop_in_progress;
   202 
   203 /* Many places require us to lock the child frame data, and then lock
   204    the locker of some random window.  Unfortunately, locking such a
   205    window might be delayed due to an arriving message, which then
   206    calls a callback inside that window that tries to lock the child
   207    frame data but doesn't finish since the child frame lock is already
   208    held, not letting the code that held the child frame lock proceed,
   209    thereby causing a deadlock.
   210 
   211    Rectifying that problem is simple: all code in a looper callback
   212    must lock the child frame data with this macro instead.
   213 
   214    IOW, if some other code is already running with the child frame
   215    lock held, don't interfere: wait until it's finished before
   216    continuing.  */
   217 #define CHILD_FRAME_LOCK_INSIDE_LOOPER_CALLBACK         \
   218   if (child_frame_lock.LockWithTimeout (200) != B_OK)   \
   219     {                                                   \
   220       /* The Haiku equivalent of XPutBackEvent.  */     \
   221       if (CurrentMessage ())                            \
   222         PostMessage (CurrentMessage ());                \
   223     }                                                   \
   224   else
   225 
   226 /* This could be a private API, but it's used by (at least) the Qt
   227    port, so it's probably here to stay.  */
   228 extern status_t get_subpixel_antialiasing (bool *);
   229 
   230 /* The ID of the thread the BApplication is running in.  */
   231 static thread_id app_thread;
   232 
   233 _Noreturn void
   234 gui_abort (const char *msg)
   235 {
   236   fprintf (stderr, "Abort in GUI code: %s\n", msg);
   237   fprintf (stderr, "Under Haiku, Emacs cannot recover from errors in GUI code\n");
   238   fprintf (stderr, "App Server disconnects usually manifest as bitmap "
   239            "initialization failures or lock failures.");
   240   abort ();
   241 }
   242 
   243 struct be_popup_menu_data
   244 {
   245   int x, y;
   246   BPopUpMenu *menu;
   247 };
   248 
   249 static int32
   250 be_popup_menu_thread_entry (void *thread_data)
   251 {
   252   struct be_popup_menu_data *data;
   253   struct haiku_dummy_event dummy;
   254   BMenuItem *it;
   255 
   256   data = (struct be_popup_menu_data *) thread_data;
   257 
   258   it = data->menu->Go (BPoint (data->x, data->y));
   259 
   260   if (it)
   261     popup_track_message = it->Message ();
   262   else
   263     popup_track_message = NULL;
   264 
   265   haiku_write (DUMMY_EVENT, &dummy);
   266   return 0;
   267 }
   268 
   269 /* Convert a raw character RAW produced by the keycode KEY into a key
   270    symbol and place it in KEYSYM.
   271 
   272    If RAW cannot be converted into a keysym, value is 0.  If RAW can
   273    be converted into a keysym, but it should be ignored, value is -1.
   274 
   275    Any other value means success, and that the keysym should be used
   276    instead of mapping the keycode into a character.  */
   277 
   278 static int
   279 keysym_from_raw_char (int32 raw, int32 key, unsigned *code)
   280 {
   281   switch (raw)
   282     {
   283     case B_BACKSPACE:
   284       *code = KEY_BACKSPACE;
   285       break;
   286     case B_RETURN:
   287       *code = KEY_RETURN;
   288       break;
   289     case B_TAB:
   290       *code = KEY_TAB;
   291       break;
   292     case B_ESCAPE:
   293       *code = KEY_ESCAPE;
   294       break;
   295     case B_LEFT_ARROW:
   296       *code = KEY_LEFT_ARROW;
   297       break;
   298     case B_RIGHT_ARROW:
   299       *code = KEY_RIGHT_ARROW;
   300       break;
   301     case B_UP_ARROW:
   302       *code = KEY_UP_ARROW;
   303       break;
   304     case B_DOWN_ARROW:
   305       *code = KEY_DOWN_ARROW;
   306       break;
   307     case B_INSERT:
   308       *code = KEY_INSERT;
   309       break;
   310     case B_DELETE:
   311       *code = KEY_DELETE;
   312       break;
   313     case B_HOME:
   314       *code = KEY_HOME;
   315       break;
   316     case B_END:
   317       *code = KEY_END;
   318       break;
   319     case B_PAGE_UP:
   320       *code = KEY_PAGE_UP;
   321       break;
   322     case B_PAGE_DOWN:
   323       *code = KEY_PAGE_DOWN;
   324       break;
   325 
   326     case B_FUNCTION_KEY:
   327       *code = KEY_F1 + key - 2;
   328 
   329       if (*code - KEY_F1 == 12)
   330         *code = KEY_PRINT;
   331       else if (*code - KEY_F1 == 13)
   332         /* Okay, Scroll Lock is a bit too much: keyboard.c doesn't
   333            know about it yet, and it shouldn't, since that's a
   334            modifier key.
   335 
   336            *code = KEY_SCROLL_LOCK; */
   337         return -1;
   338       else if (*code - KEY_F1 == 14)
   339         *code = KEY_PAUSE;
   340 
   341       break;
   342 
   343     case B_HANGUL:
   344       *code = KEY_HANGUL;
   345       break;
   346     case B_HANGUL_HANJA:
   347       *code = KEY_HANGUL_HANJA;
   348       break;
   349     case B_KATAKANA_HIRAGANA:
   350       *code = KEY_HIRIGANA_KATAGANA;
   351       break;
   352     case B_HANKAKU_ZENKAKU:
   353       *code = KEY_ZENKAKU_HANKAKU;
   354       break;
   355 
   356     default:
   357       return 0;
   358     }
   359 
   360   return 1;
   361 }
   362 
   363 static void
   364 map_key (char *chars, int32 offset, uint32_t *c)
   365 {
   366   int size = chars[offset++];
   367   switch (size)
   368     {
   369     case 0:
   370       break;
   371 
   372     case 1:
   373       *c = chars[offset];
   374       break;
   375 
   376     default:
   377       {
   378         char str[5];
   379         int i = (size <= 4) ? size : 4;
   380         strncpy (str, &(chars[offset]), i);
   381         str[i] = '0';
   382         *c = BUnicodeChar::FromUTF8 ((char *) &str);
   383         break;
   384       }
   385     }
   386 }
   387 
   388 static void
   389 map_shift (uint32_t kc, uint32_t *ch)
   390 {
   391   if (!key_map_lock.Lock ())
   392     gui_abort ("Failed to lock keymap");
   393   if (!key_map)
   394     get_key_map (&key_map, &key_chars);
   395   if (!key_map)
   396     return;
   397   if (kc >= 128)
   398     return;
   399 
   400   int32_t m = key_map->shift_map[kc];
   401   map_key (key_chars, m, ch);
   402   key_map_lock.Unlock ();
   403 }
   404 
   405 static void
   406 map_caps (uint32_t kc, uint32_t *ch)
   407 {
   408   if (!key_map_lock.Lock ())
   409     gui_abort ("Failed to lock keymap");
   410   if (!key_map)
   411     get_key_map (&key_map, &key_chars);
   412   if (!key_map)
   413     return;
   414   if (kc >= 128)
   415     return;
   416 
   417   int32_t m = key_map->caps_map[kc];
   418   map_key (key_chars, m, ch);
   419   key_map_lock.Unlock ();
   420 }
   421 
   422 static void
   423 map_caps_shift (uint32_t kc, uint32_t *ch)
   424 {
   425   if (!key_map_lock.Lock ())
   426     gui_abort ("Failed to lock keymap");
   427   if (!key_map)
   428     get_key_map (&key_map, &key_chars);
   429   if (!key_map)
   430     return;
   431   if (kc >= 128)
   432     return;
   433 
   434   int32_t m = key_map->caps_shift_map[kc];
   435   map_key (key_chars, m, ch);
   436   key_map_lock.Unlock ();
   437 }
   438 
   439 static void
   440 map_normal (uint32_t kc, uint32_t *ch)
   441 {
   442   if (!key_map_lock.Lock ())
   443     gui_abort ("Failed to lock keymap");
   444   if (!key_map)
   445     get_key_map (&key_map, &key_chars);
   446   if (!key_map)
   447     return;
   448   if (kc >= 128)
   449     return;
   450 
   451   int32_t m = key_map->normal_map[kc];
   452   map_key (key_chars, m, ch);
   453   key_map_lock.Unlock ();
   454 }
   455 
   456 static BRect
   457 get_zoom_rect (BWindow *window)
   458 {
   459   BScreen screen;
   460   BDeskbar deskbar;
   461   BRect screen_frame;
   462   BRect frame;
   463   BRect deskbar_frame;
   464   BRect window_frame;
   465   BRect decorator_frame;
   466 
   467   if (!screen.IsValid ())
   468     gui_abort ("Failed to calculate screen rect");
   469 
   470   screen_frame = frame = screen.Frame ();
   471   deskbar_frame = deskbar.Frame ();
   472 
   473   if (!(modifiers () & B_SHIFT_KEY) && !deskbar.IsAutoHide ())
   474     {
   475       switch (deskbar.Location ())
   476         {
   477         case B_DESKBAR_TOP:
   478           frame.top = deskbar_frame.bottom + 2;
   479           break;
   480 
   481         case B_DESKBAR_BOTTOM:
   482         case B_DESKBAR_LEFT_BOTTOM:
   483         case B_DESKBAR_RIGHT_BOTTOM:
   484           frame.bottom = deskbar_frame.top - 2;
   485           break;
   486 
   487         case B_DESKBAR_LEFT_TOP:
   488           if (!deskbar.IsExpanded ())
   489             frame.top = deskbar_frame.bottom + 2;
   490           else if (!deskbar.IsAlwaysOnTop ()
   491                    && !deskbar.IsAutoRaise ())
   492             frame.left = deskbar_frame.right + 2;
   493           break;
   494 
   495         default:
   496           if (deskbar.IsExpanded ()
   497               && !deskbar.IsAlwaysOnTop ()
   498               && !deskbar.IsAutoRaise ())
   499             frame.right = deskbar_frame.left - 2;
   500         }
   501     }
   502 
   503   if (window)
   504     {
   505       window_frame = window->Frame ();
   506       decorator_frame = window->DecoratorFrame ();
   507 
   508       frame.top += (window_frame.top
   509                     - decorator_frame.top);
   510       frame.bottom -= (decorator_frame.bottom
   511                        - window_frame.bottom);
   512       frame.left += (window_frame.left
   513                      - decorator_frame.left);
   514       frame.right -= (decorator_frame.right
   515                       - window_frame.right);
   516 
   517       if (frame.top > deskbar_frame.bottom
   518           || frame.bottom < deskbar_frame.top)
   519         {
   520           frame.left = screen_frame.left + (window_frame.left
   521                                             - decorator_frame.left);
   522           frame.right = screen_frame.right - (decorator_frame.right
   523                                               - window_frame.right);
   524         }
   525     }
   526 
   527   return frame;
   528 }
   529 
   530 /* Invisible window used to get B_SCREEN_CHANGED events.  */
   531 class EmacsScreenChangeMonitor : public BWindow
   532 {
   533   BRect previous_screen_frame;
   534 
   535 public:
   536   EmacsScreenChangeMonitor (void) : BWindow (BRect (-100, -100, 0, 0), "",
   537                                              B_NO_BORDER_WINDOW_LOOK,
   538                                              B_FLOATING_ALL_WINDOW_FEEL,
   539                                              B_AVOID_FRONT | B_AVOID_FOCUS)
   540   {
   541     BScreen screen (this);
   542 
   543     if (!screen.IsValid ())
   544       return;
   545 
   546     previous_screen_frame = screen.Frame ();
   547 
   548     /* Immediately show this window upon creation.  It will not steal
   549        the focus or become visible.  */
   550     Show ();
   551 
   552     if (!LockLooper ())
   553       return;
   554 
   555     Hide ();
   556     UnlockLooper ();
   557   }
   558 
   559   void
   560   DispatchMessage (BMessage *msg, BHandler *handler)
   561   {
   562     struct haiku_screen_changed_event rq;
   563     BRect frame;
   564 
   565     if (msg->what == B_SCREEN_CHANGED)
   566       {
   567         if (msg->FindInt64 ("when", &rq.when) != B_OK)
   568           rq.when = 0;
   569 
   570         if (msg->FindRect ("frame", &frame) != B_OK
   571             || frame != previous_screen_frame)
   572           {
   573             haiku_write (SCREEN_CHANGED_EVENT, &rq);
   574 
   575             if (frame.IsValid ())
   576               previous_screen_frame = frame;
   577           }
   578       }
   579 
   580     BWindow::DispatchMessage (msg, handler);
   581   }
   582 };
   583 
   584 class Emacs : public BApplication
   585 {
   586 public:
   587   BMessage settings;
   588   bool settings_valid_p;
   589   EmacsScreenChangeMonitor *monitor;
   590 
   591   Emacs (void) : BApplication ("application/x-vnd.GNU-emacs"),
   592                  settings_valid_p (false)
   593   {
   594     BPath settings_path;
   595 
   596     if (find_directory (B_USER_SETTINGS_DIRECTORY, &settings_path) != B_OK)
   597       return;
   598 
   599     settings_path.Append (PACKAGE_NAME);
   600 
   601     BEntry entry (settings_path.Path ());
   602     BFile settings_file (&entry, B_READ_ONLY | B_CREATE_FILE);
   603 
   604     if (settings.Unflatten (&settings_file) != B_OK)
   605       return;
   606 
   607     settings_valid_p = true;
   608     monitor = new EmacsScreenChangeMonitor;
   609   }
   610 
   611   ~Emacs (void)
   612   {
   613     if (monitor->LockLooper ())
   614       monitor->Quit ();
   615     else
   616       delete monitor;
   617   }
   618 
   619   void
   620   AboutRequested (void)
   621   {
   622     BAlert *about = new BAlert (PACKAGE_NAME,
   623                                 PACKAGE_STRING
   624                                 "\nThe extensible, self-documenting, real-time display editor.",
   625                                 "Close");
   626     about->Go ();
   627   }
   628 
   629   bool
   630   QuitRequested (void)
   631   {
   632     struct haiku_app_quit_requested_event rq;
   633     struct haiku_session_manager_reply reply;
   634     int32 reply_type;
   635 
   636     haiku_write (APP_QUIT_REQUESTED_EVENT, &rq);
   637 
   638     if (read_port (port_emacs_to_session_manager,
   639                    &reply_type, &reply, sizeof reply) < B_OK)
   640       /* Return true so the system kills us, since there's no real
   641          alternative if this read fails.  */
   642       return true;
   643 
   644     return reply.quit_reply;
   645   }
   646 
   647   void
   648   MessageReceived (BMessage *msg)
   649   {
   650     struct haiku_clipboard_changed_event rq;
   651 
   652     if (msg->what == QUIT_APPLICATION)
   653       Quit ();
   654     else if (msg->what == B_CLIPBOARD_CHANGED)
   655       haiku_write (CLIPBOARD_CHANGED_EVENT, &rq);
   656     else if (msg->what == B_KEY_MAP_LOADED)
   657       {
   658         /* Install the new keymap.  Or rather, clear key_map -- Emacs
   659            will fetch it again from the main thread the next time it
   660            is needed.  */
   661         if (key_map_lock.Lock ())
   662           {
   663             if (key_map)
   664               free (key_map);
   665 
   666             if (key_chars)
   667               free (key_chars);
   668 
   669             key_map = NULL;
   670             key_chars = NULL;
   671             key_map_lock.Unlock ();
   672           }
   673       }
   674     else
   675       BApplication::MessageReceived (msg);
   676   }
   677 };
   678 
   679 class EmacsWindow : public BWindow
   680 {
   681 public:
   682   struct child_frame
   683   {
   684     struct child_frame *next;
   685     int xoff, yoff;
   686     EmacsWindow *window;
   687   } *subset_windows;
   688 
   689   EmacsWindow *parent;
   690   BRect pre_fullscreen_rect;
   691   BRect pre_zoom_rect;
   692   int x_before_zoom;
   693   int y_before_zoom;
   694   bool shown_flag;
   695   volatile bool was_shown_p;
   696   bool menu_bar_active_p;
   697   bool override_redirect_p;
   698   window_look pre_override_redirect_look;
   699   window_feel pre_override_redirect_feel;
   700   uint32 pre_override_redirect_workspaces;
   701   int window_id;
   702   bool *menus_begun;
   703   enum haiku_z_group z_group;
   704   bool tooltip_p;
   705   enum haiku_fullscreen_mode fullscreen_mode;
   706 
   707   EmacsWindow () : BWindow (BRect (0, 0, 0, 0), "", B_TITLED_WINDOW_LOOK,
   708                             B_NORMAL_WINDOW_FEEL, B_NO_SERVER_SIDE_WINDOW_MODIFIERS),
   709                    subset_windows (NULL),
   710                    parent (NULL),
   711                    x_before_zoom (INT_MIN),
   712                    y_before_zoom (INT_MIN),
   713                    shown_flag (false),
   714                    was_shown_p (false),
   715                    menu_bar_active_p (false),
   716                    override_redirect_p (false),
   717                    menus_begun (NULL),
   718                    z_group (Z_GROUP_NONE),
   719                    tooltip_p (false),
   720                    fullscreen_mode (FULLSCREEN_MODE_NONE)
   721   {
   722     /* This pulse rate is used by scroll bars for repeating a button
   723        action while a button is held down.  */
   724     SetPulseRate (30000);
   725   }
   726 
   727   ~EmacsWindow ()
   728   {
   729     if (!child_frame_lock.Lock ())
   730       gui_abort ("Failed to lock child frame state lock");
   731     struct child_frame *next;
   732     for (struct child_frame *f = subset_windows; f; f = next)
   733       {
   734         if (f->window->LockLooper ())
   735           gui_abort ("Failed to lock looper for unparent");
   736         f->window->Unparent ();
   737         f->window->UnlockLooper ();
   738         next = f->next;
   739         delete f;
   740       }
   741 
   742     if (this->parent)
   743       UnparentAndUnlink ();
   744     child_frame_lock.Unlock ();
   745   }
   746 
   747   void
   748   RecomputeFeel (void)
   749   {
   750     if (override_redirect_p || tooltip_p)
   751       SetFeel (kMenuWindowFeel);
   752     else if (parent)
   753       SetFeel (B_FLOATING_SUBSET_WINDOW_FEEL);
   754     else if (z_group == Z_GROUP_ABOVE)
   755       SetFeel (B_FLOATING_ALL_WINDOW_FEEL);
   756     else
   757       SetFeel (B_NORMAL_WINDOW_FEEL);
   758   }
   759 
   760   void
   761   UpwardsSubset (EmacsWindow *w)
   762   {
   763     for (; w; w = w->parent)
   764       AddToSubset (w);
   765   }
   766 
   767   void
   768   UpwardsSubsetChildren (EmacsWindow *w)
   769   {
   770     if (!LockLooper ())
   771       gui_abort ("Failed to lock looper for subset");
   772     if (!child_frame_lock.Lock ())
   773       gui_abort ("Failed to lock child frame state lock");
   774     UpwardsSubset (w);
   775     for (struct child_frame *f = subset_windows; f;
   776          f = f->next)
   777       f->window->UpwardsSubsetChildren (w);
   778     child_frame_lock.Unlock ();
   779     UnlockLooper ();
   780   }
   781 
   782   void
   783   UpwardsUnSubset (EmacsWindow *w)
   784   {
   785     for (; w; w = w->parent)
   786       RemoveFromSubset (w);
   787   }
   788 
   789   void
   790   UpwardsUnSubsetChildren (EmacsWindow *w)
   791   {
   792     if (!LockLooper ())
   793       gui_abort ("Failed to lock looper for unsubset");
   794     if (!child_frame_lock.Lock ())
   795       gui_abort ("Failed to lock child frame state lock");
   796     UpwardsUnSubset (w);
   797     for (struct child_frame *f = subset_windows; f;
   798          f = f->next)
   799       f->window->UpwardsUnSubsetChildren (w);
   800     child_frame_lock.Unlock ();
   801     UnlockLooper ();
   802   }
   803 
   804   void
   805   Unparent (void)
   806   {
   807     EmacsWindow *parent;
   808 
   809     if (!child_frame_lock.Lock ())
   810       gui_abort ("Failed to lock child frame state lock");
   811 
   812     parent = this->parent;
   813     this->parent = NULL;
   814     RecomputeFeel ();
   815     UpwardsUnSubsetChildren (parent);
   816     this->RemoveFromSubset (this);
   817     child_frame_lock.Unlock ();
   818   }
   819 
   820   void
   821   UnparentAndUnlink (void)
   822   {
   823     if (!child_frame_lock.Lock ())
   824       gui_abort ("Failed to lock child frame state lock");
   825     this->parent->UnlinkChild (this);
   826     this->Unparent ();
   827     child_frame_lock.Unlock ();
   828   }
   829 
   830   void
   831   UnlinkChild (EmacsWindow *window)
   832   {
   833     struct child_frame *last = NULL;
   834     struct child_frame *tem = subset_windows;
   835 
   836     for (; tem; last = tem, tem = tem->next)
   837       {
   838         if (tem->window == window)
   839           {
   840             if (last)
   841               last->next = tem->next;
   842             else
   843               subset_windows = tem->next;
   844             delete tem;
   845             return;
   846           }
   847       }
   848 
   849     gui_abort ("Failed to unlink child frame");
   850   }
   851 
   852   void
   853   ParentTo (EmacsWindow *window)
   854   {
   855     if (!child_frame_lock.Lock ())
   856       gui_abort ("Failed to lock child frame state lock");
   857 
   858     if (this->parent)
   859       UnparentAndUnlink ();
   860 
   861     this->parent = window;
   862     RecomputeFeel ();
   863     this->AddToSubset (this);
   864     if (!IsHidden () && this->parent)
   865       UpwardsSubsetChildren (parent);
   866     window->LinkChild (this);
   867 
   868     child_frame_lock.Unlock ();
   869   }
   870 
   871   void
   872   LinkChild (EmacsWindow *window)
   873   {
   874     struct child_frame *f = new struct child_frame;
   875 
   876     for (struct child_frame *f = subset_windows; f;
   877          f = f->next)
   878       {
   879         if (window == f->window)
   880           gui_abort ("Trying to link a child frame that is already present");
   881       }
   882 
   883     f->window = window;
   884     f->next = subset_windows;
   885     f->xoff = -1;
   886     f->yoff = -1;
   887 
   888     subset_windows = f;
   889   }
   890 
   891   void
   892   MoveToIncludingFrame (int x, int y)
   893   {
   894     BRect decorator, frame;
   895 
   896     decorator = DecoratorFrame ();
   897     frame = Frame ();
   898 
   899     MoveTo (x + frame.left - decorator.left,
   900             y + frame.top - decorator.top);
   901   }
   902 
   903   void
   904   DoMove (struct child_frame *f)
   905   {
   906     BRect frame = this->Frame ();
   907     f->window->MoveToIncludingFrame (frame.left + f->xoff,
   908                                      frame.top + f->yoff);
   909   }
   910 
   911   void
   912   DoUpdateWorkspace (struct child_frame *f)
   913   {
   914     f->window->SetWorkspaces (this->Workspaces ());
   915   }
   916 
   917   void
   918   MoveChild (EmacsWindow *window, int xoff, int yoff,
   919              int weak_p)
   920   {
   921     if (!child_frame_lock.Lock ())
   922       gui_abort ("Failed to lock child frame state lock");
   923 
   924     for (struct child_frame *f = subset_windows; f;
   925          f = f->next)
   926       {
   927         if (window == f->window)
   928           {
   929             f->xoff = xoff;
   930             f->yoff = yoff;
   931             if (!weak_p)
   932               DoMove (f);
   933 
   934             child_frame_lock.Unlock ();
   935             return;
   936           }
   937       }
   938 
   939     child_frame_lock.Unlock ();
   940     gui_abort ("Trying to move a child frame that doesn't exist");
   941   }
   942 
   943   void
   944   WindowActivated (bool activated)
   945   {
   946     struct haiku_activation_event rq;
   947     rq.window = this;
   948     rq.activated_p = activated;
   949 
   950     haiku_write (ACTIVATION, &rq);
   951   }
   952 
   953   void
   954   MessageReceived (BMessage *msg)
   955   {
   956     if (msg->WasDropped ())
   957       {
   958         BPoint whereto;
   959         int64 threadid;
   960         struct haiku_drag_and_drop_event rq;
   961 
   962         if (msg->FindInt64 ("emacs:thread_id", &threadid) == B_OK
   963             && threadid == find_thread (NULL))
   964           return;
   965 
   966         whereto = msg->DropPoint ();
   967 
   968         this->ConvertFromScreen (&whereto);
   969 
   970         rq.window = this;
   971         rq.message = DetachCurrentMessage ();
   972         rq.x = whereto.x;
   973         rq.y = whereto.y;
   974 
   975         haiku_write (DRAG_AND_DROP_EVENT, &rq);
   976       }
   977     else if (msg->GetPointer ("menuptr"))
   978       {
   979         struct haiku_menu_bar_select_event rq;
   980 
   981         rq.window = this;
   982         rq.ptr = (void *) msg->GetPointer ("menuptr");
   983 
   984         haiku_write (MENU_BAR_SELECT_EVENT, &rq);
   985       }
   986     else
   987       BWindow::MessageReceived (msg);
   988   }
   989 
   990   void
   991   DispatchMessage (BMessage *msg, BHandler *handler)
   992   {
   993     if (msg->what == B_KEY_DOWN || msg->what == B_KEY_UP)
   994       {
   995         struct haiku_key_event rq;
   996 
   997         /* Pass through key events to the regular dispatch mechanism
   998            if the menu bar active, so that key navigation can work.  */
   999         if (menu_bar_active_p)
  1000           {
  1001             BWindow::DispatchMessage (msg, handler);
  1002             return;
  1003           }
  1004 
  1005         rq.window = this;
  1006 
  1007         int32 raw, key;
  1008         int ret;
  1009         msg->FindInt32 ("raw_char", &raw);
  1010         msg->FindInt32 ("key", &key);
  1011         msg->FindInt64 ("when", &rq.time);
  1012 
  1013         rq.modifiers = 0;
  1014         uint32_t mods = modifiers ();
  1015 
  1016         if (mods & B_SHIFT_KEY)
  1017           rq.modifiers |= HAIKU_MODIFIER_SHIFT;
  1018 
  1019         if (mods & B_CONTROL_KEY)
  1020           rq.modifiers |= HAIKU_MODIFIER_CTRL;
  1021 
  1022         if (mods & B_COMMAND_KEY)
  1023           rq.modifiers |= HAIKU_MODIFIER_ALT;
  1024 
  1025         if (mods & B_OPTION_KEY)
  1026           rq.modifiers |= HAIKU_MODIFIER_SUPER;
  1027 
  1028         ret = keysym_from_raw_char (raw, key, &rq.keysym);
  1029 
  1030         if (!ret)
  1031           rq.keysym = 0;
  1032 
  1033         if (ret < 0)
  1034           return;
  1035 
  1036         rq.multibyte_char = 0;
  1037 
  1038         if (!rq.keysym)
  1039           {
  1040             if (mods & B_SHIFT_KEY)
  1041               {
  1042                 if (mods & B_CAPS_LOCK)
  1043                   map_caps_shift (key, &rq.multibyte_char);
  1044                 else
  1045                   map_shift (key, &rq.multibyte_char);
  1046               }
  1047             else
  1048               {
  1049                 if (mods & B_CAPS_LOCK)
  1050                   map_caps (key, &rq.multibyte_char);
  1051                 else
  1052                   map_normal (key, &rq.multibyte_char);
  1053               }
  1054           }
  1055 
  1056         haiku_write (msg->what == B_KEY_DOWN ? KEY_DOWN : KEY_UP, &rq);
  1057       }
  1058     else if (msg->what == B_MOUSE_WHEEL_CHANGED)
  1059       {
  1060         struct haiku_wheel_move_event rq;
  1061         rq.window = this;
  1062         rq.modifiers = 0;
  1063 
  1064         uint32_t mods = modifiers ();
  1065 
  1066         if (mods & B_SHIFT_KEY)
  1067           rq.modifiers |= HAIKU_MODIFIER_SHIFT;
  1068 
  1069         if (mods & B_CONTROL_KEY)
  1070           rq.modifiers |= HAIKU_MODIFIER_CTRL;
  1071 
  1072         if (mods & B_COMMAND_KEY)
  1073           rq.modifiers |= HAIKU_MODIFIER_ALT;
  1074 
  1075         if (mods & B_OPTION_KEY)
  1076           rq.modifiers |= HAIKU_MODIFIER_SUPER;
  1077 
  1078         float dx, dy;
  1079         if (msg->FindFloat ("be:wheel_delta_x", &dx) == B_OK &&
  1080             msg->FindFloat ("be:wheel_delta_y", &dy) == B_OK)
  1081           {
  1082             rq.delta_x = dx;
  1083             rq.delta_y = dy;
  1084 
  1085             haiku_write (WHEEL_MOVE_EVENT, &rq);
  1086           };
  1087       }
  1088     else if (msg->what == SEND_MOVE_FRAME_EVENT)
  1089       FrameMoved (Frame ().LeftTop ());
  1090     else if (msg->what == B_SCREEN_CHANGED)
  1091       {
  1092         if (fullscreen_mode != FULLSCREEN_MODE_NONE)
  1093           SetFullscreen (fullscreen_mode);
  1094 
  1095         BWindow::DispatchMessage (msg, handler);
  1096       }
  1097     else
  1098       BWindow::DispatchMessage (msg, handler);
  1099   }
  1100 
  1101   void
  1102   MenusBeginning (void)
  1103   {
  1104     struct haiku_menu_bar_state_event rq;
  1105 
  1106     rq.window = this;
  1107     if (!menus_begun)
  1108       haiku_write (MENU_BAR_OPEN, &rq);
  1109     else
  1110       *menus_begun = true;
  1111 
  1112     menu_bar_active_p = true;
  1113   }
  1114 
  1115   void
  1116   MenusEnded ()
  1117   {
  1118     struct haiku_menu_bar_state_event rq;
  1119     rq.window = this;
  1120 
  1121     haiku_write (MENU_BAR_CLOSE, &rq);
  1122     menu_bar_active_p = false;
  1123   }
  1124 
  1125   void
  1126   FrameResized (float newWidth, float newHeight)
  1127   {
  1128     struct haiku_resize_event rq;
  1129     rq.window = this;
  1130     rq.width = newWidth + 1.0f;
  1131     rq.height = newHeight + 1.0f;
  1132 
  1133     haiku_write (FRAME_RESIZED, &rq);
  1134     BWindow::FrameResized (newWidth, newHeight);
  1135   }
  1136 
  1137   void
  1138   FrameMoved (BPoint new_position)
  1139   {
  1140     struct haiku_move_event rq;
  1141     BRect frame, decorator_frame;
  1142     struct child_frame *f;
  1143 
  1144     if (fullscreen_mode == FULLSCREEN_MODE_WIDTH
  1145         && new_position.x != 0)
  1146       {
  1147         MoveTo (0, new_position.y);
  1148         return;
  1149       }
  1150 
  1151     if (fullscreen_mode == FULLSCREEN_MODE_HEIGHT
  1152         && new_position.y != 0)
  1153       {
  1154         MoveTo (new_position.x, 0);
  1155         return;
  1156       }
  1157 
  1158     rq.window = this;
  1159     rq.x = std::lrint (new_position.x);
  1160     rq.y = std::lrint (new_position.y);
  1161 
  1162     frame = Frame ();
  1163     decorator_frame = DecoratorFrame ();
  1164 
  1165     rq.decorator_width
  1166       = std::lrint (frame.left - decorator_frame.left);
  1167     rq.decorator_height
  1168       = std::lrint (frame.top - decorator_frame.top);
  1169 
  1170     haiku_write (MOVE_EVENT, &rq);
  1171 
  1172     CHILD_FRAME_LOCK_INSIDE_LOOPER_CALLBACK
  1173       {
  1174         for (f = subset_windows; f; f = f->next)
  1175           DoMove (f);
  1176         child_frame_lock.Unlock ();
  1177 
  1178         BWindow::FrameMoved (new_position);
  1179       }
  1180   }
  1181 
  1182   void
  1183   WorkspacesChanged (uint32_t old, uint32_t n)
  1184   {
  1185     struct child_frame *f;
  1186 
  1187     CHILD_FRAME_LOCK_INSIDE_LOOPER_CALLBACK
  1188       {
  1189         for (f = subset_windows; f; f = f->next)
  1190           DoUpdateWorkspace (f);
  1191 
  1192         child_frame_lock.Unlock ();
  1193       }
  1194   }
  1195 
  1196   void
  1197   EmacsMoveTo (int x, int y)
  1198   {
  1199     if (!child_frame_lock.Lock ())
  1200       gui_abort ("Failed to lock child frame state lock");
  1201 
  1202     if (!this->parent)
  1203       this->MoveToIncludingFrame (x, y);
  1204     else
  1205       this->parent->MoveChild (this, x, y, 0);
  1206     child_frame_lock.Unlock ();
  1207   }
  1208 
  1209   bool
  1210   QuitRequested ()
  1211   {
  1212     struct haiku_quit_requested_event rq;
  1213     rq.window = this;
  1214     haiku_write (QUIT_REQUESTED, &rq);
  1215     return false;
  1216   }
  1217 
  1218   void
  1219   Minimize (bool minimized_p)
  1220   {
  1221     struct haiku_iconification_event rq;
  1222 
  1223     rq.window = this;
  1224     rq.iconified_p = !parent && minimized_p;
  1225     haiku_write (ICONIFICATION, &rq);
  1226 
  1227     BWindow::Minimize (minimized_p);
  1228   }
  1229 
  1230   void
  1231   EmacsHide (void)
  1232   {
  1233     if (this->IsHidden ())
  1234       return;
  1235     if (!child_frame_lock.Lock ())
  1236       gui_abort ("Failed to lock child frame state lock");
  1237 
  1238     Hide ();
  1239     if (this->parent)
  1240       UpwardsUnSubsetChildren (this->parent);
  1241 
  1242     child_frame_lock.Unlock ();
  1243   }
  1244 
  1245   void
  1246   EmacsShow (void)
  1247   {
  1248     if (!this->IsHidden ())
  1249       return;
  1250 
  1251     if (!child_frame_lock.Lock ())
  1252       gui_abort ("Failed to lock child frame state lock");
  1253 
  1254     if (!was_shown_p)
  1255       {
  1256         /* This window is being shown for the first time, which means
  1257            Show will unlock the looper.  In this case, it should be
  1258            locked again, since the looper is unlocked when the window
  1259            is first created.  */
  1260 
  1261         if (!LockLooper ())
  1262           gui_abort ("Failed to lock looper during first window show");
  1263         was_shown_p = true;
  1264       }
  1265 
  1266     if (this->parent)
  1267       shown_flag = 1;
  1268     Show ();
  1269     if (this->parent)
  1270       UpwardsSubsetChildren (this->parent);
  1271 
  1272     child_frame_lock.Unlock ();
  1273   }
  1274 
  1275   BRect
  1276   ClearFullscreen (enum haiku_fullscreen_mode target_mode)
  1277   {
  1278     BRect original_frame;
  1279 
  1280     switch (fullscreen_mode)
  1281       {
  1282       case FULLSCREEN_MODE_MAXIMIZED:
  1283         original_frame = pre_zoom_rect;
  1284 
  1285         if (target_mode == FULLSCREEN_MODE_NONE)
  1286           BWindow::Zoom (pre_zoom_rect.LeftTop (),
  1287                          BE_RECT_WIDTH (pre_zoom_rect) - 1,
  1288                          BE_RECT_HEIGHT (pre_zoom_rect) - 1);
  1289         break;
  1290 
  1291       case FULLSCREEN_MODE_BOTH:
  1292       case FULLSCREEN_MODE_HEIGHT:
  1293       case FULLSCREEN_MODE_WIDTH:
  1294         original_frame = pre_fullscreen_rect;
  1295         SetFlags (Flags () & ~(B_NOT_MOVABLE
  1296                                | B_NOT_ZOOMABLE
  1297                                | B_NOT_RESIZABLE));
  1298 
  1299         if (target_mode != FULLSCREEN_MODE_NONE)
  1300           goto out;
  1301 
  1302         MoveTo (pre_fullscreen_rect.LeftTop ());
  1303         ResizeTo (BE_RECT_WIDTH (pre_fullscreen_rect) - 1,
  1304                   BE_RECT_HEIGHT (pre_fullscreen_rect) - 1);
  1305         break;
  1306 
  1307       case FULLSCREEN_MODE_NONE:
  1308         original_frame = Frame ();
  1309         break;
  1310       }
  1311 
  1312   out:
  1313     fullscreen_mode = FULLSCREEN_MODE_NONE;
  1314     return original_frame;
  1315   }
  1316 
  1317   BRect
  1318   FullscreenRectForMode (enum haiku_fullscreen_mode mode)
  1319   {
  1320     BScreen screen (this);
  1321     BRect frame;
  1322 
  1323     if (!screen.IsValid ())
  1324       return BRect (0, 0, 0, 0);
  1325 
  1326     frame = screen.Frame ();
  1327 
  1328     if (mode == FULLSCREEN_MODE_HEIGHT)
  1329       frame.right -= BE_RECT_WIDTH (frame) / 2;
  1330     else if (mode == FULLSCREEN_MODE_WIDTH)
  1331       frame.bottom -= BE_RECT_HEIGHT (frame) / 2;
  1332 
  1333     return frame;
  1334   }
  1335 
  1336   void
  1337   SetFullscreen (enum haiku_fullscreen_mode mode)
  1338   {
  1339     BRect zoom_rect, frame;
  1340 
  1341     frame = ClearFullscreen (mode);
  1342 
  1343     switch (mode)
  1344       {
  1345       case FULLSCREEN_MODE_MAXIMIZED:
  1346         pre_zoom_rect = frame;
  1347         zoom_rect = get_zoom_rect (this);
  1348         BWindow::Zoom (zoom_rect.LeftTop (),
  1349                        BE_RECT_WIDTH (zoom_rect) - 1,
  1350                        BE_RECT_HEIGHT (zoom_rect) - 1);
  1351         break;
  1352 
  1353       case FULLSCREEN_MODE_BOTH:
  1354         SetFlags (Flags () | B_NOT_MOVABLE);
  1355         FALLTHROUGH;
  1356 
  1357       case FULLSCREEN_MODE_HEIGHT:
  1358       case FULLSCREEN_MODE_WIDTH:
  1359         SetFlags (Flags () | B_NOT_ZOOMABLE | B_NOT_RESIZABLE);
  1360         pre_fullscreen_rect = frame;
  1361         zoom_rect = FullscreenRectForMode (mode);
  1362         ResizeTo (BE_RECT_WIDTH (zoom_rect) - 1,
  1363                   BE_RECT_HEIGHT (zoom_rect) - 1);
  1364         MoveTo (zoom_rect.left, zoom_rect.top);
  1365         break;
  1366 
  1367       case FULLSCREEN_MODE_NONE:
  1368         break;
  1369       }
  1370 
  1371     fullscreen_mode = mode;
  1372   }
  1373 
  1374   void
  1375   Zoom (BPoint origin, float width, float height)
  1376   {
  1377     struct haiku_zoom_event rq;
  1378 
  1379     rq.window = this;
  1380     rq.fullscreen_mode = fullscreen_mode;
  1381     haiku_write (ZOOM_EVENT, &rq);
  1382   }
  1383 
  1384   void
  1385   OffsetChildRect (BRect *r, EmacsWindow *c)
  1386   {
  1387     if (!child_frame_lock.Lock ())
  1388       gui_abort ("Failed to lock child frame state lock");
  1389 
  1390     for (struct child_frame *f; f; f = f->next)
  1391       if (f->window == c)
  1392         {
  1393           r->top -= f->yoff;
  1394           r->bottom -= f->yoff;
  1395           r->left -= f->xoff;
  1396           r->right -= f->xoff;
  1397           child_frame_lock.Unlock ();
  1398           return;
  1399         }
  1400 
  1401     child_frame_lock.Lock ();
  1402     gui_abort ("Trying to calculate offsets for a child frame that doesn't exist");
  1403   }
  1404 };
  1405 
  1406 class EmacsMenuBar : public BMenuBar
  1407 {
  1408   bool tracking_p;
  1409 
  1410 public:
  1411   EmacsMenuBar () : BMenuBar (BRect (0, 0, 0, 0), NULL)
  1412   {
  1413   }
  1414 
  1415   void
  1416   AttachedToWindow (void)
  1417   {
  1418     BWindow *window = Window ();
  1419 
  1420     window->SetKeyMenuBar (this);
  1421   }
  1422 
  1423   void
  1424   FrameResized (float newWidth, float newHeight)
  1425   {
  1426     struct haiku_menu_bar_resize_event rq;
  1427     rq.window = this->Window ();
  1428     rq.height = std::lrint (newHeight + 1);
  1429     rq.width = std::lrint (newWidth + 1);
  1430 
  1431     haiku_write (MENU_BAR_RESIZE, &rq);
  1432     BMenuBar::FrameResized (newWidth, newHeight);
  1433   }
  1434 
  1435   void
  1436   MouseDown (BPoint point)
  1437   {
  1438     struct haiku_menu_bar_click_event rq;
  1439     EmacsWindow *ew = (EmacsWindow *) Window ();
  1440 
  1441     rq.window = ew;
  1442     rq.x = std::lrint (point.x);
  1443     rq.y = std::lrint (point.y);
  1444 
  1445     if (!ew->menu_bar_active_p)
  1446       haiku_write (MENU_BAR_CLICK, &rq);
  1447     else
  1448       BMenuBar::MouseDown (point);
  1449   }
  1450 
  1451   void
  1452   MouseMoved (BPoint point, uint32 transit, const BMessage *msg)
  1453   {
  1454     struct haiku_menu_bar_left_event rq;
  1455 
  1456     if (transit == B_EXITED_VIEW)
  1457       {
  1458         rq.x = std::lrint (point.x);
  1459         rq.y = std::lrint (point.y);
  1460         rq.window = this->Window ();
  1461 
  1462         haiku_write (MENU_BAR_LEFT, &rq);
  1463       }
  1464 
  1465     BMenuBar::MouseMoved (point, transit, msg);
  1466   }
  1467 
  1468   void
  1469   MessageReceived (BMessage *msg)
  1470   {
  1471     BRect frame;
  1472     BPoint pt, l;
  1473     EmacsWindow *window;
  1474     bool menus_begun;
  1475 
  1476     if (msg->what == SHOW_MENU_BAR)
  1477       {
  1478         window = (EmacsWindow *) Window ();
  1479         frame = Frame ();
  1480         pt = frame.LeftTop ();
  1481         l = pt;
  1482         menus_begun = false;
  1483         Parent ()->ConvertToScreen (&pt);
  1484 
  1485         window->menus_begun = &menus_begun;
  1486         set_mouse_position (pt.x, pt.y);
  1487         BMenuBar::MouseDown (l);
  1488         window->menus_begun = NULL;
  1489 
  1490         if (!menus_begun)
  1491           msg->SendReply (msg);
  1492         else
  1493           msg->SendReply (BE_MENU_BAR_OPEN);
  1494       }
  1495     else if (msg->what == REPLAY_MENU_BAR)
  1496       {
  1497         window = (EmacsWindow *) Window ();
  1498         menus_begun = false;
  1499         window->menus_begun = &menus_begun;
  1500 
  1501         if (msg->FindPoint ("emacs:point", &pt) == B_OK)
  1502           BMenuBar::MouseDown (pt);
  1503 
  1504         window->menus_begun = NULL;
  1505 
  1506         if (!menus_begun)
  1507           msg->SendReply (msg);
  1508         else
  1509           msg->SendReply (BE_MENU_BAR_OPEN);
  1510       }
  1511     else
  1512       BMenuBar::MessageReceived (msg);
  1513   }
  1514 };
  1515 
  1516 class EmacsView : public BView
  1517 {
  1518 public:
  1519   int looper_locked_count;
  1520   BRegion sb_region;
  1521   BRegion invalid_region;
  1522 
  1523   BView *offscreen_draw_view;
  1524   BBitmap *offscreen_draw_bitmap_1;
  1525   BBitmap *copy_bitmap;
  1526 
  1527 #ifdef USE_BE_CAIRO
  1528   cairo_surface_t *cr_surface;
  1529   cairo_t *cr_context;
  1530   BLocker cr_surface_lock;
  1531 #endif
  1532 
  1533   BMessage *wait_for_release_message;
  1534   int64 grabbed_buttons;
  1535   BScreen screen;
  1536   bool use_frame_synchronization;
  1537 
  1538   EmacsView () : BView (BRect (0, 0, 0, 0), "Emacs",
  1539                         B_FOLLOW_NONE, B_WILL_DRAW),
  1540                  looper_locked_count (0),
  1541                  offscreen_draw_view (NULL),
  1542                  offscreen_draw_bitmap_1 (NULL),
  1543                  copy_bitmap (NULL),
  1544 #ifdef USE_BE_CAIRO
  1545                  cr_surface (NULL),
  1546                  cr_context (NULL),
  1547 #endif
  1548                  wait_for_release_message (NULL),
  1549                  grabbed_buttons (0),
  1550                  use_frame_synchronization (false)
  1551   {
  1552 
  1553   }
  1554 
  1555   ~EmacsView ()
  1556   {
  1557     if (wait_for_release_message)
  1558       {
  1559         wait_for_release_message->SendReply (wait_for_release_message);
  1560         delete wait_for_release_message;
  1561       }
  1562 
  1563     TearDownDoubleBuffering ();
  1564 
  1565     if (!grab_view_locker.Lock ())
  1566       gui_abort ("Couldn't lock grab view locker");
  1567     if (grab_view == this)
  1568       grab_view = NULL;
  1569     grab_view_locker.Unlock ();
  1570   }
  1571 
  1572   void
  1573   SetFrameSynchronization (bool sync)
  1574   {
  1575     if (LockLooper ())
  1576       {
  1577         use_frame_synchronization = sync;
  1578         UnlockLooper ();
  1579       }
  1580   }
  1581 
  1582   void
  1583   MessageReceived (BMessage *msg)
  1584   {
  1585     uint32 buttons;
  1586     BLooper *looper = Looper ();
  1587 
  1588     if (msg->what == WAIT_FOR_RELEASE)
  1589       {
  1590         if (wait_for_release_message)
  1591           gui_abort ("Wait for release message already exists");
  1592 
  1593         GetMouse (NULL, &buttons, false);
  1594 
  1595         if (!buttons)
  1596           msg->SendReply (msg);
  1597         else
  1598           wait_for_release_message = looper->DetachCurrentMessage ();
  1599       }
  1600     else if (msg->what == RELEASE_NOW)
  1601       {
  1602         if (wait_for_release_message)
  1603           wait_for_release_message->SendReply (msg);
  1604 
  1605         delete wait_for_release_message;
  1606         wait_for_release_message = NULL;
  1607       }
  1608     else
  1609       BView::MessageReceived (msg);
  1610   }
  1611 
  1612 #ifdef USE_BE_CAIRO
  1613   void
  1614   DetachCairoSurface (void)
  1615   {
  1616     if (!cr_surface_lock.Lock ())
  1617       gui_abort ("Could not lock cr surface during detachment");
  1618     if (!cr_surface)
  1619       gui_abort ("Trying to detach window cr surface when none exists");
  1620     cairo_destroy (cr_context);
  1621     cairo_surface_destroy (cr_surface);
  1622     cr_surface = NULL;
  1623     cr_context = NULL;
  1624     cr_surface_lock.Unlock ();
  1625   }
  1626 
  1627   void
  1628   AttachCairoSurface (void)
  1629   {
  1630     if (!cr_surface_lock.Lock ())
  1631       gui_abort ("Could not lock cr surface during attachment");
  1632     if (cr_surface)
  1633       gui_abort ("Trying to attach cr surface when one already exists");
  1634     BRect bounds = offscreen_draw_bitmap_1->Bounds ();
  1635 
  1636     cr_surface = cairo_image_surface_create_for_data
  1637       ((unsigned char *) offscreen_draw_bitmap_1->Bits (),
  1638        CAIRO_FORMAT_ARGB32, BE_RECT_WIDTH (bounds),
  1639        BE_RECT_HEIGHT (bounds),
  1640        offscreen_draw_bitmap_1->BytesPerRow ());
  1641     if (!cr_surface)
  1642       gui_abort ("Cr surface allocation failed for double-buffered view");
  1643 
  1644     cr_context = cairo_create (cr_surface);
  1645     if (!cr_context)
  1646       gui_abort ("cairo_t allocation failed for double-buffered view");
  1647     cr_surface_lock.Unlock ();
  1648   }
  1649 #endif
  1650 
  1651   void
  1652   TearDownDoubleBuffering (void)
  1653   {
  1654     if (offscreen_draw_view)
  1655       {
  1656         if (Window ())
  1657           ClearViewBitmap ();
  1658         if (copy_bitmap)
  1659           {
  1660             delete copy_bitmap;
  1661             copy_bitmap = NULL;
  1662           }
  1663         if (!looper_locked_count)
  1664           if (!offscreen_draw_view->LockLooper ())
  1665             gui_abort ("Failed to lock offscreen draw view");
  1666 #ifdef USE_BE_CAIRO
  1667         if (cr_surface)
  1668           DetachCairoSurface ();
  1669 #endif
  1670         offscreen_draw_view->RemoveSelf ();
  1671         delete offscreen_draw_view;
  1672         offscreen_draw_view = NULL;
  1673         delete offscreen_draw_bitmap_1;
  1674         offscreen_draw_bitmap_1 = NULL;
  1675       }
  1676    }
  1677 
  1678   void
  1679   AfterResize (void)
  1680   {
  1681     if (offscreen_draw_view)
  1682       {
  1683         if (!LockLooper ())
  1684           gui_abort ("Failed to lock looper after resize");
  1685 
  1686         if (!offscreen_draw_view->LockLooper ())
  1687           gui_abort ("Failed to lock offscreen draw view after resize");
  1688 #ifdef USE_BE_CAIRO
  1689         DetachCairoSurface ();
  1690 #endif
  1691         offscreen_draw_view->RemoveSelf ();
  1692         delete offscreen_draw_bitmap_1;
  1693         offscreen_draw_bitmap_1 = new BBitmap (Frame (), B_RGBA32, 1);
  1694         if (offscreen_draw_bitmap_1->InitCheck () != B_OK)
  1695           gui_abort ("Offscreen draw bitmap initialization failed");
  1696 
  1697         BRect frame = Frame ();
  1698 
  1699         offscreen_draw_view->MoveTo (frame.left, frame.top);
  1700         offscreen_draw_view->ResizeTo (BE_RECT_WIDTH (frame),
  1701                                        BE_RECT_HEIGHT (frame));
  1702         offscreen_draw_bitmap_1->AddChild (offscreen_draw_view);
  1703 #ifdef USE_BE_CAIRO
  1704         AttachCairoSurface ();
  1705 #endif
  1706 
  1707         if (looper_locked_count)
  1708           offscreen_draw_bitmap_1->Lock ();
  1709 
  1710         UnlockLooper ();
  1711       }
  1712   }
  1713 
  1714   void
  1715   Draw (BRect expose_bounds)
  1716   {
  1717     struct haiku_expose_event rq;
  1718     EmacsWindow *w = (EmacsWindow *) Window ();
  1719 
  1720     if (w->shown_flag && offscreen_draw_view)
  1721       {
  1722         PushState ();
  1723         SetDrawingMode (B_OP_ERASE);
  1724         FillRect (Frame ());
  1725         PopState ();
  1726         return;
  1727       }
  1728 
  1729     if (!offscreen_draw_view)
  1730       {
  1731         if (sb_region.Contains (std::lrint (expose_bounds.left),
  1732                                 std::lrint (expose_bounds.top)) &&
  1733             sb_region.Contains (std::lrint (expose_bounds.right),
  1734                                 std::lrint (expose_bounds.top)) &&
  1735             sb_region.Contains (std::lrint (expose_bounds.left),
  1736                                 std::lrint (expose_bounds.bottom)) &&
  1737             sb_region.Contains (std::lrint (expose_bounds.right),
  1738                                 std::lrint (expose_bounds.bottom)))
  1739           return;
  1740 
  1741         rq.x = std::floor (expose_bounds.left);
  1742         rq.y = std::floor (expose_bounds.top);
  1743         rq.width = std::ceil (expose_bounds.right - expose_bounds.left + 1);
  1744         rq.height = std::ceil (expose_bounds.bottom - expose_bounds.top + 1);
  1745         if (!rq.width)
  1746           rq.width = 1;
  1747         if (!rq.height)
  1748           rq.height = 1;
  1749         rq.window = this->Window ();
  1750 
  1751         haiku_write (FRAME_EXPOSED, &rq);
  1752       }
  1753   }
  1754 
  1755   void
  1756   FlipBuffers (void)
  1757   {
  1758     EmacsWindow *w;
  1759     if (!LockLooper ())
  1760       gui_abort ("Failed to lock looper during buffer flip");
  1761     if (!offscreen_draw_view)
  1762       gui_abort ("Failed to lock offscreen view during buffer flip");
  1763 
  1764     offscreen_draw_view->Sync ();
  1765     w = (EmacsWindow *) Window ();
  1766     w->shown_flag = 0;
  1767 
  1768     if (copy_bitmap &&
  1769         copy_bitmap->Bounds () != offscreen_draw_bitmap_1->Bounds ())
  1770       {
  1771         delete copy_bitmap;
  1772         copy_bitmap = NULL;
  1773       }
  1774     if (!copy_bitmap)
  1775       {
  1776         copy_bitmap = new BBitmap (offscreen_draw_bitmap_1);
  1777         SetViewBitmap (copy_bitmap, Frame (),
  1778                        Frame (), B_FOLLOW_NONE, 0);
  1779       }
  1780     else
  1781       copy_bitmap->ImportBits (offscreen_draw_bitmap_1);
  1782 
  1783     if (copy_bitmap->InitCheck () != B_OK)
  1784       gui_abort ("Failed to init copy bitmap during buffer flip");
  1785 
  1786     /* Wait for VBLANK.  If responding to the invalidation or buffer
  1787        flipping takes longer than the blanking period, we lose.  */
  1788     if (use_frame_synchronization)
  1789       screen.WaitForRetrace ();
  1790 
  1791     Invalidate (&invalid_region);
  1792     invalid_region.MakeEmpty ();
  1793     UnlockLooper ();
  1794     return;
  1795   }
  1796 
  1797   void
  1798   SetUpDoubleBuffering (void)
  1799   {
  1800     if (!LockLooper ())
  1801       gui_abort ("Failed to lock self setting up double buffering");
  1802     if (offscreen_draw_view)
  1803       gui_abort ("Failed to lock offscreen view setting up double buffering");
  1804 
  1805     offscreen_draw_bitmap_1 = new BBitmap (Frame (), B_RGBA32, 1);
  1806     if (offscreen_draw_bitmap_1->InitCheck () != B_OK)
  1807       gui_abort ("Failed to init offscreen bitmap");
  1808 #ifdef USE_BE_CAIRO
  1809     AttachCairoSurface ();
  1810 #endif
  1811     offscreen_draw_view = new BView (Frame (), NULL, B_FOLLOW_NONE, B_WILL_DRAW);
  1812     offscreen_draw_bitmap_1->AddChild (offscreen_draw_view);
  1813 
  1814     if (looper_locked_count)
  1815       {
  1816         if (!offscreen_draw_bitmap_1->Lock ())
  1817           gui_abort ("Failed to lock bitmap after double buffering was set up");
  1818       }
  1819 
  1820     invalid_region.MakeEmpty ();
  1821     UnlockLooper ();
  1822     Invalidate ();
  1823   }
  1824 
  1825   void
  1826   MouseMoved (BPoint point, uint32 transit, const BMessage *drag_msg)
  1827   {
  1828     struct haiku_mouse_motion_event rq;
  1829     int64 threadid;
  1830     EmacsWindow *window;
  1831 
  1832     window = (EmacsWindow *) Window ();
  1833 
  1834     if (transit == B_EXITED_VIEW)
  1835       rq.just_exited_p = true;
  1836     else
  1837       rq.just_exited_p = false;
  1838 
  1839     rq.x = point.x;
  1840     rq.y = point.y;
  1841     rq.window = window;
  1842     rq.time = system_time ();
  1843 
  1844     if (drag_msg && (drag_msg->IsSourceRemote ()
  1845                      || drag_msg->FindInt64 ("emacs:thread_id",
  1846                                              &threadid) != B_OK
  1847                      || threadid != find_thread (NULL)))
  1848       rq.dnd_message = true;
  1849     else
  1850       rq.dnd_message = false;
  1851 
  1852     if (!grab_view_locker.Lock ())
  1853       gui_abort ("Couldn't lock grab view locker");
  1854 
  1855     if (grab_view && this != grab_view)
  1856       {
  1857         grab_view_locker.Unlock ();
  1858         return;
  1859       }
  1860 
  1861     grab_view_locker.Unlock ();
  1862 
  1863     haiku_write (MOUSE_MOTION, &rq);
  1864   }
  1865 
  1866   void
  1867   BasicMouseDown (BPoint point, BView *scroll_bar, BMessage *message)
  1868   {
  1869     struct haiku_button_event rq;
  1870     int64 when;
  1871     int32 mods, buttons, button;
  1872 
  1873     if (message->FindInt64 ("when", &when) != B_OK
  1874         || message->FindInt32 ("modifiers", &mods) != B_OK
  1875         || message->FindInt32 ("buttons", &buttons) != B_OK)
  1876       return;
  1877 
  1878     /* Find which button was pressed by comparing the previous button
  1879        mask to the current one.  This assumes that B_MOUSE_DOWN will
  1880        be sent for each button press.  */
  1881     button = buttons & ~grabbed_buttons;
  1882     grabbed_buttons = buttons;
  1883 
  1884     if (!scroll_bar)
  1885       {
  1886         if (!grab_view_locker.Lock ())
  1887           gui_abort ("Couldn't lock grab view locker");
  1888         grab_view = this;
  1889         grab_view_locker.Unlock ();
  1890       }
  1891 
  1892     rq.window = this->Window ();
  1893     rq.scroll_bar = scroll_bar;
  1894 
  1895     if (button == B_PRIMARY_MOUSE_BUTTON)
  1896       rq.btn_no = 0;
  1897     else if (button == B_SECONDARY_MOUSE_BUTTON)
  1898       rq.btn_no = 2;
  1899     else if (button == B_TERTIARY_MOUSE_BUTTON)
  1900       rq.btn_no = 1;
  1901     else
  1902       /* We don't know which button was pressed.  This usually happens
  1903          when a B_MOUSE_UP is sent to a view that didn't receive a
  1904          corresponding B_MOUSE_DOWN event, so simply ignore the
  1905          message.  */
  1906       return;
  1907 
  1908     rq.x = point.x;
  1909     rq.y = point.y;
  1910     rq.modifiers = 0;
  1911 
  1912     if (mods & B_SHIFT_KEY)
  1913       rq.modifiers |= HAIKU_MODIFIER_SHIFT;
  1914 
  1915     if (mods & B_CONTROL_KEY)
  1916       rq.modifiers |= HAIKU_MODIFIER_CTRL;
  1917 
  1918     if (mods & B_COMMAND_KEY)
  1919       rq.modifiers |= HAIKU_MODIFIER_ALT;
  1920 
  1921     if (mods & B_OPTION_KEY)
  1922       rq.modifiers |= HAIKU_MODIFIER_SUPER;
  1923 
  1924     if (!scroll_bar)
  1925       SetMouseEventMask (B_POINTER_EVENTS, (B_LOCK_WINDOW_FOCUS
  1926                                             | B_NO_POINTER_HISTORY));
  1927 
  1928     rq.time = when;
  1929     haiku_write (BUTTON_DOWN, &rq);
  1930   }
  1931 
  1932   void
  1933   MouseDown (BPoint point)
  1934   {
  1935     BMessage *msg;
  1936     BLooper *looper;
  1937 
  1938     looper = Looper ();
  1939     msg = (looper
  1940            ? looper->CurrentMessage ()
  1941            : NULL);
  1942 
  1943     if (msg)
  1944       BasicMouseDown (point, NULL, msg);
  1945   }
  1946 
  1947   void
  1948   BasicMouseUp (BPoint point, BView *scroll_bar, BMessage *message)
  1949   {
  1950     struct haiku_button_event rq;
  1951     int64 when;
  1952     int32 mods, button, buttons;
  1953 
  1954     if (message->FindInt64 ("when", &when) != B_OK
  1955         || message->FindInt32 ("modifiers", &mods) != B_OK
  1956         || message->FindInt32 ("buttons", &buttons) != B_OK)
  1957       return;
  1958 
  1959     if (!scroll_bar)
  1960       {
  1961         if (!grab_view_locker.Lock ())
  1962           gui_abort ("Couldn't lock grab view locker");
  1963         if (!buttons)
  1964           grab_view = NULL;
  1965         grab_view_locker.Unlock ();
  1966       }
  1967 
  1968     button = (grabbed_buttons & ~buttons);
  1969     grabbed_buttons = buttons;
  1970 
  1971     if (wait_for_release_message)
  1972       {
  1973         if (!grabbed_buttons)
  1974           {
  1975             wait_for_release_message->SendReply (wait_for_release_message);
  1976             delete wait_for_release_message;
  1977             wait_for_release_message = NULL;
  1978           }
  1979 
  1980         return;
  1981       }
  1982 
  1983     rq.window = this->Window ();
  1984     rq.scroll_bar = scroll_bar;
  1985 
  1986     if (button == B_PRIMARY_MOUSE_BUTTON)
  1987       rq.btn_no = 0;
  1988     else if (button == B_SECONDARY_MOUSE_BUTTON)
  1989       rq.btn_no = 2;
  1990     else if (button == B_TERTIARY_MOUSE_BUTTON)
  1991       rq.btn_no = 1;
  1992     else
  1993       return;
  1994 
  1995     rq.x = point.x;
  1996     rq.y = point.y;
  1997 
  1998     rq.modifiers = 0;
  1999     if (mods & B_SHIFT_KEY)
  2000       rq.modifiers |= HAIKU_MODIFIER_SHIFT;
  2001 
  2002     if (mods & B_CONTROL_KEY)
  2003       rq.modifiers |= HAIKU_MODIFIER_CTRL;
  2004 
  2005     if (mods & B_COMMAND_KEY)
  2006       rq.modifiers |= HAIKU_MODIFIER_ALT;
  2007 
  2008     if (mods & B_OPTION_KEY)
  2009       rq.modifiers |= HAIKU_MODIFIER_SUPER;
  2010 
  2011     rq.time = when;
  2012     haiku_write (BUTTON_UP, &rq);
  2013   }
  2014 
  2015   void
  2016   MouseUp (BPoint point)
  2017   {
  2018     BMessage *msg;
  2019     BLooper *looper;
  2020 
  2021     looper = Looper ();
  2022     msg = (looper
  2023            ? looper->CurrentMessage ()
  2024            : NULL);
  2025 
  2026     if (msg)
  2027       BasicMouseUp (point, NULL, msg);
  2028   }
  2029 };
  2030 
  2031 class EmacsScrollBar : public BScrollBar
  2032 {
  2033 public:
  2034   int dragging;
  2035   bool horizontal;
  2036   enum haiku_scroll_bar_part current_part;
  2037   float old_value;
  2038   scroll_bar_info info;
  2039 
  2040   /* How many button events were passed to the parent without
  2041      release.  */
  2042   int handle_button_count;
  2043   bool in_overscroll;
  2044   bool can_overscroll;
  2045   bool maybe_overscroll;
  2046   BPoint last_overscroll;
  2047   int last_reported_overscroll_value;
  2048   int max_value, real_max_value;
  2049   int overscroll_start_value;
  2050   bigtime_t repeater_start;
  2051   EmacsView *parent;
  2052 
  2053   EmacsScrollBar (int x, int y, int x1, int y1, bool horizontal_p,
  2054                   EmacsView *parent)
  2055     : BScrollBar (BRect (x, y, x1, y1), NULL, NULL, 0, 0, horizontal_p ?
  2056                   B_HORIZONTAL : B_VERTICAL),
  2057       dragging (0),
  2058       handle_button_count (0),
  2059       in_overscroll (false),
  2060       can_overscroll (false),
  2061       maybe_overscroll (false),
  2062       parent (parent)
  2063   {
  2064     BView *vw = (BView *) this;
  2065     vw->SetResizingMode (B_FOLLOW_NONE);
  2066     horizontal = horizontal_p;
  2067     get_scroll_bar_info (&info);
  2068     SetSteps (5000, 10000);
  2069   }
  2070 
  2071   void
  2072   MessageReceived (BMessage *msg)
  2073   {
  2074     int32 portion, range, dragging, value;
  2075     float proportion;
  2076 
  2077     if (msg->what == SCROLL_BAR_UPDATE)
  2078       {
  2079         portion = msg->GetInt32 ("emacs:portion", 0);
  2080         range = msg->GetInt32 ("emacs:range", 0);
  2081         dragging = msg->GetInt32 ("emacs:dragging", 0);
  2082         proportion = ((range <= 0 || portion <= 0)
  2083                       ? 1.0f : (float) portion / range);
  2084         value = msg->GetInt32 ("emacs:units", 0);
  2085         can_overscroll = msg->GetBool ("emacs:overscroll", false);
  2086 
  2087         if (value < 0)
  2088           value = 0;
  2089 
  2090         if (dragging != 1)
  2091           {
  2092             if (in_overscroll || dragging != -1)
  2093               {
  2094                 /* Set the value to the smallest possible one.
  2095                    Otherwise, the call to SetRange could lead to
  2096                    spurious updates.  */
  2097                 old_value = 0;
  2098                 SetValue (0);
  2099 
  2100                 /* Unlike on Motif, PORTION isn't included in the total
  2101                    range of the scroll bar.  */
  2102 
  2103                 SetRange (0, range - portion);
  2104                 SetProportion (proportion);
  2105                 max_value = range - portion;
  2106                 real_max_value = range;
  2107 
  2108                 if (in_overscroll || value > max_value)
  2109                   value = max_value;
  2110 
  2111                 old_value = roundf (value);
  2112                 SetValue (old_value);
  2113               }
  2114             else
  2115               {
  2116                 value = Value ();
  2117 
  2118                 old_value = 0;
  2119                 SetValue (0);
  2120                 SetRange (0, range - portion);
  2121                 SetProportion (proportion);
  2122                 old_value = value;
  2123                 SetValue (value);
  2124                 max_value = range - portion;
  2125                 real_max_value = range;
  2126               }
  2127           }
  2128       }
  2129 
  2130     BScrollBar::MessageReceived (msg);
  2131   }
  2132 
  2133   void
  2134   Pulse (void)
  2135   {
  2136     struct haiku_scroll_bar_part_event rq;
  2137     BPoint point;
  2138     uint32 buttons;
  2139 
  2140     if (!dragging)
  2141       {
  2142         SetFlags (Flags () & ~B_PULSE_NEEDED);
  2143         return;
  2144       }
  2145 
  2146     if (repeater_start < system_time ())
  2147       {
  2148         GetMouse (&point, &buttons, false);
  2149 
  2150         if (ButtonRegionFor (current_part).Contains (point))
  2151           {
  2152             rq.scroll_bar = this;
  2153             rq.window = Window ();
  2154             rq.part = current_part;
  2155             haiku_write (SCROLL_BAR_PART_EVENT, &rq);
  2156           }
  2157       }
  2158 
  2159     BScrollBar::Pulse ();
  2160   }
  2161 
  2162   void
  2163   ValueChanged (float new_value)
  2164   {
  2165     struct haiku_scroll_bar_value_event rq;
  2166 
  2167     new_value = Value ();
  2168 
  2169     if (dragging)
  2170       {
  2171         if (new_value != old_value)
  2172           {
  2173             if (dragging > 1)
  2174               {
  2175                 SetValue (old_value);
  2176                 SetFlags (Flags () | B_PULSE_NEEDED);
  2177               }
  2178             else
  2179               dragging++;
  2180           }
  2181 
  2182         return;
  2183       }
  2184 
  2185     if (new_value != old_value)
  2186       {
  2187         rq.scroll_bar = this;
  2188         rq.window = Window ();
  2189         rq.position = new_value;
  2190         old_value = new_value;
  2191 
  2192         haiku_write (SCROLL_BAR_VALUE_EVENT, &rq);
  2193       }
  2194   }
  2195 
  2196   BRegion
  2197   ButtonRegionFor (enum haiku_scroll_bar_part button)
  2198   {
  2199     BRegion region;
  2200     BRect bounds;
  2201     BRect rect;
  2202     float button_size;
  2203 
  2204     bounds = Bounds ();
  2205     bounds.InsetBy (0.0, 0.0);
  2206 
  2207     if (horizontal)
  2208       button_size = bounds.Height () + 1.0f;
  2209     else
  2210       button_size = bounds.Width () + 1.0f;
  2211 
  2212     rect = BRect (bounds.left, bounds.top,
  2213                   bounds.left + button_size - 1.0f,
  2214                   bounds.top + button_size - 1.0f);
  2215 
  2216     if (button == HAIKU_SCROLL_BAR_UP_BUTTON)
  2217       {
  2218         if (!horizontal)
  2219           {
  2220             region.Include (rect);
  2221             if (info.double_arrows)
  2222               region.Include (rect.OffsetToCopy (bounds.left,
  2223                                                  bounds.bottom - 2 * button_size + 1));
  2224           }
  2225         else
  2226           {
  2227             region.Include (rect);
  2228             if (info.double_arrows)
  2229               region.Include (rect.OffsetToCopy (bounds.right - 2 * button_size,
  2230                                                  bounds.top));
  2231           }
  2232       }
  2233     else
  2234       {
  2235         if (!horizontal)
  2236           {
  2237             region.Include (rect.OffsetToCopy (bounds.left, bounds.bottom - button_size));
  2238 
  2239             if (info.double_arrows)
  2240               region.Include (rect.OffsetByCopy (0.0, button_size));
  2241           }
  2242         else
  2243           {
  2244             region.Include (rect.OffsetToCopy (bounds.right - button_size, bounds.top));
  2245 
  2246             if (info.double_arrows)
  2247               region.Include (rect.OffsetByCopy (button_size, 0.0));
  2248           }
  2249       }
  2250 
  2251     return region;
  2252   }
  2253 
  2254   void
  2255   MouseDown (BPoint pt)
  2256   {
  2257     struct haiku_scroll_bar_drag_event rq;
  2258     struct haiku_scroll_bar_part_event part;
  2259     BRegion r;
  2260     BLooper *looper;
  2261     BMessage *message;
  2262     int32 buttons, mods;
  2263 
  2264     looper = Looper ();
  2265     message = NULL;
  2266 
  2267     if (!looper)
  2268       GetMouse (&pt, (uint32 *) &buttons, false);
  2269     else
  2270       {
  2271         message = looper->CurrentMessage ();
  2272 
  2273         if (!message || message->FindInt32 ("buttons", &buttons) != B_OK)
  2274           GetMouse (&pt, (uint32 *) &buttons, false);
  2275       }
  2276 
  2277     if (message && (message->FindInt32 ("modifiers", &mods)
  2278                     == B_OK)
  2279         && mods & B_CONTROL_KEY)
  2280       {
  2281         /* Allow C-mouse-3 to split the window on a scroll bar.   */
  2282         handle_button_count += 1;
  2283         SetMouseEventMask (B_POINTER_EVENTS, (B_SUSPEND_VIEW_FOCUS
  2284                                               | B_LOCK_WINDOW_FOCUS));
  2285         parent->BasicMouseDown (ConvertToParent (pt), this, message);
  2286 
  2287         return;
  2288       }
  2289 
  2290     repeater_start = system_time () + 300000;
  2291 
  2292     if (buttons == B_PRIMARY_MOUSE_BUTTON)
  2293       {
  2294         r = ButtonRegionFor (HAIKU_SCROLL_BAR_UP_BUTTON);
  2295 
  2296         if (r.Contains (pt))
  2297           {
  2298             part.scroll_bar = this;
  2299             part.window = Window ();
  2300             part.part = HAIKU_SCROLL_BAR_UP_BUTTON;
  2301             dragging = 1;
  2302             current_part = HAIKU_SCROLL_BAR_UP_BUTTON;
  2303 
  2304             haiku_write (SCROLL_BAR_PART_EVENT, &part);
  2305             goto out;
  2306           }
  2307 
  2308         r = ButtonRegionFor (HAIKU_SCROLL_BAR_DOWN_BUTTON);
  2309 
  2310         if (r.Contains (pt))
  2311           {
  2312             part.scroll_bar = this;
  2313             part.window = Window ();
  2314             part.part = HAIKU_SCROLL_BAR_DOWN_BUTTON;
  2315             dragging = 1;
  2316             current_part = HAIKU_SCROLL_BAR_DOWN_BUTTON;
  2317 
  2318             if (Value () == max_value)
  2319               {
  2320                 SetFlags (Flags () | B_PULSE_NEEDED);
  2321                 dragging = 2;
  2322               }
  2323 
  2324             haiku_write (SCROLL_BAR_PART_EVENT, &part);
  2325             goto out;
  2326           }
  2327 
  2328         maybe_overscroll = true;
  2329       }
  2330 
  2331     rq.dragging_p = 1;
  2332     rq.window = Window ();
  2333     rq.scroll_bar = this;
  2334 
  2335     SetMouseEventMask (B_POINTER_EVENTS, (B_SUSPEND_VIEW_FOCUS
  2336                                           | B_LOCK_WINDOW_FOCUS));
  2337 
  2338     haiku_write (SCROLL_BAR_DRAG_EVENT, &rq);
  2339 
  2340   out:
  2341     BScrollBar::MouseDown (pt);
  2342   }
  2343 
  2344   void
  2345   MouseUp (BPoint pt)
  2346   {
  2347     struct haiku_scroll_bar_drag_event rq;
  2348     BMessage *msg;
  2349     BLooper *looper;
  2350 
  2351     in_overscroll = false;
  2352     maybe_overscroll = false;
  2353 
  2354     if (handle_button_count)
  2355       {
  2356         handle_button_count--;
  2357         looper = Looper ();
  2358         msg = (looper
  2359                ? looper->CurrentMessage ()
  2360                : NULL);
  2361 
  2362         if (msg)
  2363           parent->BasicMouseUp (ConvertToParent (pt),
  2364                                 this, msg);
  2365 
  2366         return;
  2367       }
  2368 
  2369     rq.dragging_p = 0;
  2370     rq.scroll_bar = this;
  2371     rq.window = Window ();
  2372 
  2373     haiku_write (SCROLL_BAR_DRAG_EVENT, &rq);
  2374     dragging = 0;
  2375 
  2376     BScrollBar::MouseUp (pt);
  2377   }
  2378 
  2379   void
  2380   MouseMoved (BPoint point, uint32 transit, const BMessage *msg)
  2381   {
  2382     struct haiku_menu_bar_left_event rq;
  2383     struct haiku_scroll_bar_value_event value_event;
  2384     int range, diff, value, trough_size;
  2385     BRect bounds;
  2386     BPoint conv;
  2387     uint32 buttons;
  2388 
  2389     GetMouse (NULL, &buttons, false);
  2390 
  2391     if (transit == B_EXITED_VIEW)
  2392       {
  2393         conv = ConvertToParent (point);
  2394 
  2395         rq.x = std::lrint (conv.x);
  2396         rq.y = std::lrint (conv.y);
  2397         rq.window = this->Window ();
  2398 
  2399         haiku_write (MENU_BAR_LEFT, &rq);
  2400       }
  2401 
  2402     if (in_overscroll)
  2403       {
  2404         if (horizontal)
  2405           diff = point.x - last_overscroll.x;
  2406         else
  2407           diff = point.y - last_overscroll.y;
  2408 
  2409         if (diff < 0)
  2410           {
  2411             in_overscroll = false;
  2412             goto allow;
  2413           }
  2414 
  2415         range = real_max_value;
  2416         bounds = Bounds ();
  2417         bounds.InsetBy (1.0, 1.0);
  2418         value = overscroll_start_value;
  2419         trough_size = (horizontal
  2420                        ? BE_RECT_WIDTH (bounds)
  2421                        : BE_RECT_HEIGHT (bounds));
  2422         trough_size -= (horizontal
  2423                         ? BE_RECT_HEIGHT (bounds)
  2424                         : BE_RECT_WIDTH (bounds)) / 2;
  2425         if (info.double_arrows)
  2426           trough_size -= (horizontal
  2427                           ? BE_RECT_HEIGHT (bounds)
  2428                           : BE_RECT_WIDTH (bounds)) / 2;
  2429 
  2430         value += ((double) range / trough_size) * diff;
  2431 
  2432         if (value != last_reported_overscroll_value)
  2433           {
  2434             last_reported_overscroll_value = value;
  2435 
  2436             value_event.scroll_bar = this;
  2437             value_event.window = Window ();
  2438             value_event.position = value;
  2439 
  2440             haiku_write (SCROLL_BAR_VALUE_EVENT, &value_event);
  2441             return;
  2442           }
  2443       }
  2444     else if (can_overscroll
  2445              && (buttons == B_PRIMARY_MOUSE_BUTTON)
  2446              && maybe_overscroll)
  2447       {
  2448         value = Value ();
  2449 
  2450         if (value >= max_value)
  2451           {
  2452             BScrollBar::MouseMoved (point, transit, msg);
  2453 
  2454             if (value == Value ())
  2455               {
  2456                 overscroll_start_value = value;
  2457                 in_overscroll = true;
  2458                 last_overscroll = point;
  2459                 last_reported_overscroll_value = value;
  2460 
  2461                 MouseMoved (point, transit, msg);
  2462                 return;
  2463               }
  2464           }
  2465       }
  2466 
  2467   allow:
  2468     BScrollBar::MouseMoved (point, transit, msg);
  2469   }
  2470 };
  2471 
  2472 class EmacsTitleMenuItem : public BMenuItem
  2473 {
  2474 public:
  2475   EmacsTitleMenuItem (const char *str) : BMenuItem (str, NULL)
  2476   {
  2477     SetEnabled (0);
  2478   }
  2479 
  2480   void
  2481   DrawContent (void)
  2482   {
  2483     BMenu *menu = Menu ();
  2484 
  2485     menu->PushState ();
  2486     menu->SetFont (be_bold_font);
  2487     menu->SetHighColor (ui_color (B_MENU_ITEM_TEXT_COLOR));
  2488     BMenuItem::DrawContent ();
  2489     menu->PopState ();
  2490   }
  2491 };
  2492 
  2493 class EmacsMenuItem : public BMenuItem
  2494 {
  2495 public:
  2496   int menu_bar_id;
  2497   void *menu_ptr;
  2498   void *wind_ptr;
  2499   char *key;
  2500   char *help;
  2501 
  2502   EmacsMenuItem (const char *key_label, const char *label,
  2503                  const char *help, BMessage *message = NULL)
  2504     : BMenuItem (label, message),
  2505       menu_bar_id (-1),
  2506       menu_ptr (NULL),
  2507       wind_ptr (NULL),
  2508       key (NULL),
  2509       help (NULL)
  2510   {
  2511     if (key_label)
  2512       key = strdup (key_label);
  2513 
  2514     if (help)
  2515       this->help = strdup (help);
  2516   }
  2517 
  2518   ~EmacsMenuItem ()
  2519   {
  2520     if (key)
  2521       free (key);
  2522     if (help)
  2523       free (help);
  2524   }
  2525 
  2526   void
  2527   DrawContent (void)
  2528   {
  2529     BMenu *menu = Menu ();
  2530 
  2531     BMenuItem::DrawContent ();
  2532 
  2533     if (key)
  2534       {
  2535         BRect r = Frame ();
  2536         int w;
  2537 
  2538         menu->PushState ();
  2539         menu->ClipToRect (r);
  2540         menu->SetFont (be_plain_font);
  2541         w = menu->StringWidth (key);
  2542         menu->MovePenTo (BPoint (BE_RECT_WIDTH (r) - w - 4,
  2543                                  menu->PenLocation ().y));
  2544         menu->DrawString (key);
  2545         menu->PopState ();
  2546       }
  2547   }
  2548 
  2549   void
  2550   GetContentSize (float *w, float *h)
  2551   {
  2552     BMenuItem::GetContentSize (w, h);
  2553     if (Menu () && key)
  2554       *w += 4 + Menu ()->StringWidth (key);
  2555   }
  2556 
  2557   void
  2558   Highlight (bool highlight_p)
  2559   {
  2560     struct haiku_menu_bar_help_event rq;
  2561     struct haiku_dummy_event dummy;
  2562     BMenu *menu = Menu ();
  2563     BRect r;
  2564     BPoint pt;
  2565     uint32 buttons;
  2566 
  2567     if (help)
  2568       menu->SetToolTip (highlight_p ? help : NULL);
  2569     else
  2570       {
  2571         rq.window = wind_ptr;
  2572         rq.mb_idx = highlight_p ? menu_bar_id : -1;
  2573         rq.highlight_p = highlight_p;
  2574         rq.data = menu_ptr;
  2575 
  2576         r = Frame ();
  2577         menu->GetMouse (&pt, &buttons);
  2578 
  2579         if (!highlight_p || r.Contains (pt))
  2580           {
  2581             if (menu_bar_id > 0)
  2582               haiku_write (MENU_BAR_HELP_EVENT, &rq);
  2583             else
  2584               {
  2585                 haiku_write_without_signal (MENU_BAR_HELP_EVENT, &rq, true);
  2586                 haiku_write (DUMMY_EVENT, &dummy);
  2587               }
  2588           }
  2589       }
  2590 
  2591     BMenuItem::Highlight (highlight_p);
  2592   }
  2593 };
  2594 
  2595 class EmacsFontPreviewDialog : public BWindow
  2596 {
  2597   BStringView text_view;
  2598   BMessenger preview_source;
  2599   BFont *current_font;
  2600   bool is_visible;
  2601 
  2602   void
  2603   DoLayout (void)
  2604   {
  2605     float width, height;
  2606 
  2607     text_view.GetPreferredSize (&width, &height);
  2608     text_view.ResizeTo (width - 1, height - 1);
  2609 
  2610     SetSizeLimits (width, width, height, height);
  2611     ResizeTo (width - 1, height - 1);
  2612   }
  2613 
  2614   bool
  2615   QuitRequested (void)
  2616   {
  2617     preview_source.SendMessage (QUIT_PREVIEW_DIALOG);
  2618 
  2619     return false;
  2620   }
  2621 
  2622   void
  2623   MessageReceived (BMessage *message)
  2624   {
  2625     int32 family, style;
  2626     uint32 flags;
  2627     font_family name;
  2628     font_style sname;
  2629     status_t rc;
  2630     const char *size_name;
  2631     int size;
  2632 
  2633     if (message->what == SET_FONT_INDICES)
  2634       {
  2635         size_name = message->FindString ("emacs:size");
  2636 
  2637         if (message->FindInt32 ("emacs:family", &family) != B_OK
  2638             || message->FindInt32 ("emacs:style", &style) != B_OK)
  2639           return;
  2640 
  2641         rc = get_font_family (family, &name, &flags);
  2642 
  2643         if (rc != B_OK)
  2644           return;
  2645 
  2646         rc = get_font_style (name, style, &sname, &flags);
  2647 
  2648         if (rc != B_OK)
  2649           return;
  2650 
  2651         if (current_font)
  2652           delete current_font;
  2653 
  2654         current_font = new BFont;
  2655         current_font->SetFamilyAndStyle (name, sname);
  2656 
  2657         if (message->GetBool ("emacs:disable_antialiasing", false))
  2658           current_font->SetFlags (B_DISABLE_ANTIALIASING);
  2659 
  2660         if (size_name && strlen (size_name))
  2661           {
  2662             size = atoi (size_name);
  2663             current_font->SetSize (size);
  2664           }
  2665 
  2666         text_view.SetFont (current_font);
  2667         DoLayout ();
  2668         return;
  2669       }
  2670 
  2671     BWindow::MessageReceived (message);
  2672   }
  2673 
  2674 public:
  2675 
  2676   EmacsFontPreviewDialog (BWindow *target)
  2677     : BWindow (BRect (45, 45, 500, 300),
  2678                "Preview font",
  2679                B_FLOATING_WINDOW_LOOK,
  2680                B_MODAL_APP_WINDOW_FEEL,
  2681                B_NOT_ZOOMABLE | B_NOT_RESIZABLE),
  2682       text_view (BRect (0, 0, 0, 0),
  2683                  NULL, "The quick brown fox "
  2684                  "jumped over the lazy dog"),
  2685       preview_source (target),
  2686       current_font (NULL)
  2687   {
  2688     AddChild (&text_view);
  2689     DoLayout ();
  2690   }
  2691 
  2692   ~EmacsFontPreviewDialog (void)
  2693   {
  2694     text_view.RemoveSelf ();
  2695 
  2696     if (current_font)
  2697       delete current_font;
  2698   }
  2699 };
  2700 
  2701 class TripleLayoutView : public BView
  2702 {
  2703   BScrollView *view_1;
  2704   BView *view_2, *view_3;
  2705 
  2706   void
  2707   FrameResized (float new_width, float new_height)
  2708   {
  2709     BRect frame;
  2710     float width, height, height_1, width_1;
  2711     float basic_height;
  2712 
  2713     frame = Frame ();
  2714 
  2715     view_2->GetPreferredSize (&width, &height);
  2716     view_3->GetPreferredSize (&width_1, &height_1);
  2717 
  2718     basic_height = height + height_1;
  2719 
  2720     view_1->MoveTo (0, 0);
  2721     view_1->ResizeTo (BE_RECT_WIDTH (frame),
  2722                       BE_RECT_HEIGHT (frame) - basic_height);
  2723     view_2->MoveTo (2, BE_RECT_HEIGHT (frame) - basic_height);
  2724     view_2->ResizeTo (BE_RECT_WIDTH (frame) - 4, height);
  2725     view_3->MoveTo (2, BE_RECT_HEIGHT (frame) - height_1);
  2726     view_3->ResizeTo (BE_RECT_WIDTH (frame) - 4, height_1);
  2727 
  2728     BView::FrameResized (new_width, new_height);
  2729   }
  2730 
  2731   /* This is called by the BSplitView.  */
  2732   BSize
  2733   MinSize (void)
  2734   {
  2735     float width, height;
  2736     float width_1, height_1;
  2737     BSize size_1;
  2738 
  2739     size_1 = view_1->MinSize ();
  2740     view_2->GetPreferredSize (&width, &height);
  2741     view_3->GetPreferredSize (&width_1, &height_1);
  2742 
  2743     return BSize (std::max (size_1.width,
  2744                             std::max (width_1, width)),
  2745                   std::max (size_1.height, height + height_1));
  2746   }
  2747 
  2748 public:
  2749   TripleLayoutView (BScrollView *first, BView *second,
  2750                     BView *third) : BView (NULL, B_FRAME_EVENTS),
  2751                                     view_1 (first),
  2752                                     view_2 (second),
  2753                                     view_3 (third)
  2754   {
  2755     FrameResized (801, 801);
  2756   }
  2757 };
  2758 
  2759 class EmacsFontSelectionDialog : public BWindow
  2760 {
  2761   BView basic_view;
  2762   BCheckBox antialias_checkbox;
  2763   BCheckBox preview_checkbox;
  2764   BSplitView split_view;
  2765   BListView font_family_pane;
  2766   BListView font_style_pane;
  2767   BScrollView font_family_scroller;
  2768   BScrollView font_style_scroller;
  2769   TripleLayoutView style_view;
  2770   BObjectList<BStringItem> all_families;
  2771   BObjectList<BStringItem> all_styles;
  2772   BButton cancel_button, ok_button;
  2773   BTextControl size_entry;
  2774   port_id comm_port;
  2775   bool allow_monospace_only;
  2776   int pending_selection_idx;
  2777   EmacsFontPreviewDialog *preview;
  2778 
  2779   void
  2780   ShowPreview (void)
  2781   {
  2782     if (!preview)
  2783       {
  2784         preview = new EmacsFontPreviewDialog (this);
  2785         preview->Show ();
  2786 
  2787         UpdatePreview ();
  2788       }
  2789   }
  2790 
  2791   void
  2792   UpdatePreview (void)
  2793   {
  2794     int family, style;
  2795     BMessage message;
  2796     BMessenger messenger (preview);
  2797 
  2798     family = font_family_pane.CurrentSelection ();
  2799     style = font_style_pane.CurrentSelection ();
  2800 
  2801     message.what = SET_FONT_INDICES;
  2802     message.AddInt32 ("emacs:family", family);
  2803     message.AddInt32 ("emacs:style", style);
  2804 
  2805     if (antialias_checkbox.Value () == B_CONTROL_ON)
  2806       message.AddBool ("emacs:disable_antialiasing", true);
  2807 
  2808     message.AddString ("emacs:size",
  2809                        size_entry.Text ());
  2810 
  2811     messenger.SendMessage (&message);
  2812   }
  2813 
  2814   void
  2815   HidePreview (void)
  2816   {
  2817     if (preview)
  2818       {
  2819         if (preview->LockLooper ())
  2820           preview->Quit ();
  2821         /* I hope this works.  */
  2822         else
  2823           delete preview;
  2824 
  2825         preview = NULL;
  2826       }
  2827   }
  2828 
  2829   void
  2830   UpdateStylesForIndex (int idx)
  2831   {
  2832     int n, i, previous_selection;
  2833     uint32 flags;
  2834     font_family family;
  2835     font_style style;
  2836     BStringItem *item;
  2837     char *current_style;
  2838 
  2839     n = all_styles.CountItems ();
  2840     current_style = NULL;
  2841     previous_selection = font_style_pane.CurrentSelection ();
  2842 
  2843     if (previous_selection >= 0)
  2844       {
  2845         item = all_styles.ItemAt (previous_selection);
  2846         current_style = strdup (item->Text ());
  2847       }
  2848 
  2849     font_style_pane.MakeEmpty ();
  2850     all_styles.MakeEmpty ();
  2851 
  2852     if (get_font_family (idx, &family, &flags) == B_OK)
  2853       {
  2854         n = count_font_styles (family);
  2855 
  2856         for (i = 0; i < n; ++i)
  2857           {
  2858             if (get_font_style (family, i, &style, &flags) == B_OK)
  2859               item = new BStringItem (style);
  2860             else
  2861               item = new BStringItem ("<error>");
  2862 
  2863             if (current_style && pending_selection_idx < 0
  2864                 && !strcmp (current_style, style))
  2865               pending_selection_idx = i;
  2866 
  2867             font_style_pane.AddItem (item);
  2868             all_styles.AddItem (item);
  2869           }
  2870       }
  2871 
  2872     if (pending_selection_idx >= 0)
  2873       {
  2874         font_style_pane.Select (pending_selection_idx);
  2875         font_style_pane.ScrollToSelection ();
  2876       }
  2877 
  2878     pending_selection_idx = -1;
  2879     UpdateForSelectedStyle ();
  2880 
  2881     if (current_style)
  2882       free (current_style);
  2883   }
  2884 
  2885   bool
  2886   QuitRequested (void)
  2887   {
  2888     struct font_selection_dialog_message rq;
  2889 
  2890     rq.cancel = true;
  2891     write_port (comm_port, 0, &rq, sizeof rq);
  2892 
  2893     return false;
  2894   }
  2895 
  2896   void
  2897   UpdateForSelectedStyle (void)
  2898   {
  2899     int style = font_style_pane.CurrentSelection ();
  2900 
  2901     if (style < 0)
  2902       ok_button.SetEnabled (false);
  2903     else
  2904       ok_button.SetEnabled (true);
  2905 
  2906     if (style >= 0 && preview)
  2907       UpdatePreview ();
  2908   }
  2909 
  2910   void
  2911   MessageReceived (BMessage *msg)
  2912   {
  2913     const char *text;
  2914     int idx;
  2915     struct font_selection_dialog_message rq;
  2916 
  2917     if (msg->what == FONT_FAMILY_SELECTED)
  2918       {
  2919         idx = font_family_pane.CurrentSelection ();
  2920         UpdateStylesForIndex (idx);
  2921       }
  2922     else if (msg->what == FONT_STYLE_SELECTED)
  2923       UpdateForSelectedStyle ();
  2924     else if (msg->what == B_OK
  2925              && font_style_pane.CurrentSelection () >= 0)
  2926       {
  2927         text = size_entry.Text ();
  2928 
  2929         rq.cancel = false;
  2930         rq.family_idx = font_family_pane.CurrentSelection ();
  2931         rq.style_idx = font_style_pane.CurrentSelection ();
  2932         rq.size = atoi (text);
  2933         rq.size_specified = rq.size > 0 || strlen (text);
  2934 
  2935         if (antialias_checkbox.Value () == B_CONTROL_ON)
  2936           rq.disable_antialias = true;
  2937         else
  2938           rq.disable_antialias = false;
  2939 
  2940         write_port (comm_port, 0, &rq, sizeof rq);
  2941       }
  2942     else if (msg->what == B_CANCEL)
  2943       {
  2944         rq.cancel = true;
  2945 
  2946         write_port (comm_port, 0, &rq, sizeof rq);
  2947       }
  2948     else if (msg->what == SET_PREVIEW_DIALOG)
  2949       {
  2950         if (preview_checkbox.Value () == B_CONTROL_OFF)
  2951           HidePreview ();
  2952         else
  2953           ShowPreview ();
  2954       }
  2955     else if (msg->what == QUIT_PREVIEW_DIALOG)
  2956       {
  2957         preview_checkbox.SetValue (B_CONTROL_OFF);
  2958         HidePreview ();
  2959       }
  2960     else if (msg->what == UPDATE_PREVIEW_DIALOG)
  2961       {
  2962         if (preview)
  2963           UpdatePreview ();
  2964       }
  2965     else if (msg->what == SET_DISABLE_ANTIALIASING)
  2966       {
  2967         if (preview)
  2968           UpdatePreview ();
  2969       }
  2970 
  2971     BWindow::MessageReceived (msg);
  2972   }
  2973 
  2974 public:
  2975 
  2976   ~EmacsFontSelectionDialog (void)
  2977   {
  2978     if (preview)
  2979       {
  2980         if (preview->LockLooper ())
  2981           preview->Quit ();
  2982         /* I hope this works.  */
  2983         else
  2984           delete preview;
  2985       }
  2986 
  2987     font_family_pane.MakeEmpty ();
  2988     font_style_pane.MakeEmpty ();
  2989 
  2990     font_family_pane.RemoveSelf ();
  2991     font_style_pane.RemoveSelf ();
  2992     antialias_checkbox.RemoveSelf ();
  2993     preview_checkbox.RemoveSelf ();
  2994     style_view.RemoveSelf ();
  2995     font_family_scroller.RemoveSelf ();
  2996     font_style_scroller.RemoveSelf ();
  2997     cancel_button.RemoveSelf ();
  2998     ok_button.RemoveSelf ();
  2999     size_entry.RemoveSelf ();
  3000     basic_view.RemoveSelf ();
  3001 
  3002     if (comm_port >= B_OK)
  3003       delete_port (comm_port);
  3004   }
  3005 
  3006   EmacsFontSelectionDialog (bool monospace_only,
  3007                             int initial_family_idx,
  3008                             int initial_style_idx,
  3009                             int initial_size,
  3010                             bool initial_antialias)
  3011     : BWindow (BRect (0, 0, 500, 500),
  3012                "Select font from list",
  3013                B_TITLED_WINDOW_LOOK,
  3014                B_MODAL_APP_WINDOW_FEEL, 0),
  3015       basic_view (NULL, 0),
  3016       antialias_checkbox ("Disable antialiasing", "Disable antialiasing",
  3017                           new BMessage (SET_DISABLE_ANTIALIASING)),
  3018       preview_checkbox ("Show preview", "Show preview",
  3019                         new BMessage (SET_PREVIEW_DIALOG)),
  3020       font_family_pane (BRect (0, 0, 0, 0), NULL,
  3021                         B_SINGLE_SELECTION_LIST,
  3022                         B_FOLLOW_ALL_SIDES),
  3023       font_style_pane (BRect (0, 0, 0, 0), NULL,
  3024                        B_SINGLE_SELECTION_LIST,
  3025                        B_FOLLOW_ALL_SIDES),
  3026       font_family_scroller (NULL, &font_family_pane,
  3027                             B_FOLLOW_LEFT | B_FOLLOW_TOP,
  3028                             0, false, true),
  3029       font_style_scroller (NULL, &font_style_pane,
  3030                            B_FOLLOW_ALL_SIDES,
  3031                            B_SUPPORTS_LAYOUT, false, true),
  3032       style_view (&font_style_scroller, &antialias_checkbox,
  3033                   &preview_checkbox),
  3034       all_families (20, true),
  3035       all_styles (20, true),
  3036       cancel_button ("Cancel", "Cancel",
  3037                      new BMessage (B_CANCEL)),
  3038       ok_button ("OK", "OK", new BMessage (B_OK)),
  3039       size_entry (NULL, "Size:", NULL,
  3040                   new BMessage (UPDATE_PREVIEW_DIALOG)),
  3041       allow_monospace_only (monospace_only),
  3042       pending_selection_idx (initial_style_idx),
  3043       preview (NULL)
  3044   {
  3045     BStringItem *family_item;
  3046     int i, n_families;
  3047     font_family name;
  3048     uint32 flags, c;
  3049     BMessage *selection;
  3050     BTextView *size_text;
  3051     char format_buffer[4];
  3052 
  3053     AddChild (&basic_view);
  3054 
  3055     basic_view.AddChild (&split_view);
  3056     basic_view.AddChild (&cancel_button);
  3057     basic_view.AddChild (&ok_button);
  3058     basic_view.AddChild (&size_entry);
  3059     split_view.AddChild (&font_family_scroller, 0.7);
  3060     split_view.AddChild (&style_view, 0.3);
  3061     style_view.AddChild (&font_style_scroller);
  3062     style_view.AddChild (&antialias_checkbox);
  3063     style_view.AddChild (&preview_checkbox);
  3064 
  3065     basic_view.SetViewUIColor (B_PANEL_BACKGROUND_COLOR);
  3066     style_view.SetViewUIColor (B_PANEL_BACKGROUND_COLOR);
  3067 
  3068     FrameResized (801, 801);
  3069     UpdateForSelectedStyle ();
  3070 
  3071     selection = new BMessage (FONT_FAMILY_SELECTED);
  3072     font_family_pane.SetSelectionMessage (selection);
  3073     selection = new BMessage (FONT_STYLE_SELECTED);
  3074     font_style_pane.SetSelectionMessage (selection);
  3075     selection = new BMessage (B_OK);
  3076     font_style_pane.SetInvocationMessage (selection);
  3077     selection = new BMessage (UPDATE_PREVIEW_DIALOG);
  3078     size_entry.SetModificationMessage (selection);
  3079 
  3080     comm_port = create_port (1, "font dialog port");
  3081 
  3082     n_families = count_font_families ();
  3083 
  3084     for (i = 0; i < n_families; ++i)
  3085       {
  3086         if (get_font_family (i, &name, &flags) == B_OK)
  3087           {
  3088             family_item = new BStringItem (name);
  3089 
  3090             all_families.AddItem (family_item);
  3091             font_family_pane.AddItem (family_item);
  3092 
  3093             family_item->SetEnabled (!allow_monospace_only
  3094                                      || flags & B_IS_FIXED);
  3095           }
  3096         else
  3097           {
  3098             family_item = new BStringItem ("<error>");
  3099 
  3100             all_families.AddItem (family_item);
  3101             font_family_pane.AddItem (family_item);
  3102           }
  3103       }
  3104 
  3105     if (initial_family_idx >= 0)
  3106       {
  3107         font_family_pane.Select (initial_family_idx);
  3108         font_family_pane.ScrollToSelection ();
  3109       }
  3110 
  3111     size_text = size_entry.TextView ();
  3112 
  3113     for (c = 0; c <= 47; ++c)
  3114       size_text->DisallowChar (c);
  3115 
  3116     for (c = 58; c <= 127; ++c)
  3117       size_text->DisallowChar (c);
  3118 
  3119     if (initial_size > 0 && initial_size < 1000)
  3120       {
  3121         sprintf (format_buffer, "%d", initial_size);
  3122         size_entry.SetText (format_buffer);
  3123       }
  3124 
  3125     if (!initial_antialias)
  3126       antialias_checkbox.SetValue (B_CONTROL_ON);
  3127   }
  3128 
  3129   void
  3130   FrameResized (float new_width, float new_height)
  3131   {
  3132     BRect frame;
  3133     float ok_height, ok_width;
  3134     float cancel_height, cancel_width;
  3135     float size_width, size_height;
  3136     float bone;
  3137     int max_height;
  3138 
  3139     ok_button.GetPreferredSize (&ok_width, &ok_height);
  3140     cancel_button.GetPreferredSize (&cancel_width,
  3141                                     &cancel_height);
  3142     size_entry.GetPreferredSize (&size_width, &size_height);
  3143 
  3144     max_height = std::max (std::max (ok_height, cancel_height),
  3145                            size_height);
  3146 
  3147     SetSizeLimits (cancel_width + ok_width + size_width + 6,
  3148                    65535, max_height + 64, 65535);
  3149     frame = Frame ();
  3150 
  3151     basic_view.ResizeTo (BE_RECT_WIDTH (frame), BE_RECT_HEIGHT (frame));
  3152     split_view.ResizeTo (BE_RECT_WIDTH (frame) - 1,
  3153                          BE_RECT_HEIGHT (frame) - 4 - max_height);
  3154 
  3155     bone = BE_RECT_HEIGHT (frame) - 2 - max_height / 2;
  3156 
  3157     ok_button.MoveTo ((BE_RECT_WIDTH (frame)
  3158                        - 4 - cancel_width - ok_width),
  3159                       bone - ok_height / 2);
  3160     cancel_button.MoveTo (BE_RECT_WIDTH (frame) - 2 - cancel_width,
  3161                           bone - cancel_height / 2);
  3162     size_entry.MoveTo (2, bone - size_height / 2);
  3163 
  3164     ok_button.ResizeTo (ok_width, ok_height);
  3165     cancel_button.ResizeTo (cancel_width, cancel_height);
  3166     size_entry.ResizeTo (std::max (size_width,
  3167                                    BE_RECT_WIDTH (frame) / 4),
  3168                          size_height);
  3169   }
  3170 
  3171   void
  3172   WaitForChoice (struct font_selection_dialog_message *msg,
  3173                  void (*process_pending_signals_function) (void),
  3174                  bool (*should_quit_function) (void))
  3175   {
  3176     int32 reply_type;
  3177     struct object_wait_info infos[2];
  3178     ssize_t status;
  3179 
  3180     infos[0].object = port_application_to_emacs;
  3181     infos[0].type = B_OBJECT_TYPE_PORT;
  3182     infos[0].events = B_EVENT_READ;
  3183 
  3184     infos[1].object = comm_port;
  3185     infos[1].type = B_OBJECT_TYPE_PORT;
  3186     infos[1].events = B_EVENT_READ;
  3187 
  3188     while (true)
  3189       {
  3190         status = wait_for_objects (infos, 2);
  3191 
  3192         if (status < B_OK)
  3193           continue;
  3194 
  3195         if (infos[1].events & B_EVENT_READ)
  3196           {
  3197             if (read_port (comm_port, &reply_type,
  3198                            msg, sizeof *msg) >= B_OK)
  3199               return;
  3200 
  3201             goto cancel;
  3202           }
  3203 
  3204         if (infos[0].events & B_EVENT_READ)
  3205           process_pending_signals_function ();
  3206 
  3207         if (should_quit_function ())
  3208           goto cancel;
  3209 
  3210         infos[0].events = B_EVENT_READ;
  3211         infos[1].events = B_EVENT_READ;
  3212       }
  3213 
  3214   cancel:
  3215     msg->cancel = true;
  3216     return;
  3217   }
  3218 
  3219   status_t
  3220   InitCheck (void)
  3221   {
  3222     return comm_port >= B_OK ? B_OK : comm_port;
  3223   }
  3224 };
  3225 
  3226 class EmacsFilePanelCallbackLooper : public BLooper
  3227 {
  3228   port_id comm_port;
  3229 
  3230   void
  3231   MessageReceived (BMessage *msg)
  3232   {
  3233     const char *str_path, *name;
  3234     char *file_name, *str_buf;
  3235     BEntry entry;
  3236     BPath path;
  3237     entry_ref ref;
  3238     int32 old_what;
  3239 
  3240     if (msg->what == FILE_PANEL_SELECTION
  3241         || ((msg->FindInt32 ("old_what", &old_what) == B_OK
  3242              && old_what == FILE_PANEL_SELECTION)))
  3243       {
  3244         file_name = NULL;
  3245 
  3246         if (msg->FindRef ("refs", &ref) == B_OK
  3247             && entry.SetTo (&ref, 0) == B_OK
  3248             && entry.GetPath (&path) == B_OK)
  3249           {
  3250             str_path = path.Path ();
  3251 
  3252             if (str_path)
  3253               file_name = strdup (str_path);
  3254           }
  3255         else if (msg->FindRef ("directory", &ref) == B_OK
  3256                  && entry.SetTo (&ref, 0) == B_OK
  3257                  && entry.GetPath (&path) == B_OK)
  3258           {
  3259             name = msg->GetString ("name");
  3260             str_path = path.Path ();
  3261 
  3262             if (name)
  3263               {
  3264                 str_buf = (char *) alloca (std::strlen (str_path)
  3265                                            + std::strlen (name) + 2);
  3266                 snprintf (str_buf, std::strlen (str_path)
  3267                           + std::strlen (name) + 2, "%s/%s",
  3268                           str_path, name);
  3269                 file_name = strdup (str_buf);
  3270               }
  3271           }
  3272 
  3273         write_port (comm_port, 0, &file_name, sizeof file_name);
  3274       }
  3275 
  3276     BLooper::MessageReceived (msg);
  3277   }
  3278 
  3279 public:
  3280   EmacsFilePanelCallbackLooper (void) : BLooper ()
  3281   {
  3282     comm_port = create_port (1, "file panel port");
  3283   }
  3284 
  3285   ~EmacsFilePanelCallbackLooper (void)
  3286   {
  3287     delete_port (comm_port);
  3288   }
  3289 
  3290   char *
  3291   ReadFileName (void (*process_pending_signals_function) (void))
  3292   {
  3293     object_wait_info infos[2];
  3294     ssize_t status;
  3295     int32 reply_type;
  3296     char *file_name;
  3297 
  3298     file_name = NULL;
  3299 
  3300     infos[0].object = port_application_to_emacs;
  3301     infos[0].type = B_OBJECT_TYPE_PORT;
  3302     infos[0].events = B_EVENT_READ;
  3303 
  3304     infos[1].object = comm_port;
  3305     infos[1].type = B_OBJECT_TYPE_PORT;
  3306     infos[1].events = B_EVENT_READ;
  3307 
  3308     while (true)
  3309       {
  3310         status = wait_for_objects (infos, 2);
  3311 
  3312         if (status == B_INTERRUPTED || status == B_WOULD_BLOCK)
  3313           continue;
  3314 
  3315         if (infos[0].events & B_EVENT_READ)
  3316           process_pending_signals_function ();
  3317 
  3318         if (infos[1].events & B_EVENT_READ)
  3319           {
  3320             status = read_port (comm_port,
  3321                                 &reply_type, &file_name,
  3322                                 sizeof file_name);
  3323 
  3324             if (status < B_OK)
  3325               file_name = NULL;
  3326 
  3327             goto out;
  3328           }
  3329 
  3330         infos[0].events = B_EVENT_READ;
  3331         infos[1].events = B_EVENT_READ;
  3332       }
  3333 
  3334   out:
  3335     return file_name;
  3336   }
  3337 
  3338   status_t
  3339   InitCheck (void)
  3340   {
  3341     return comm_port >= B_OK ? B_OK : comm_port;
  3342   }
  3343 };
  3344 
  3345 /* A view that is added as a child of a tooltip's text view, and
  3346    prevents motion events from reaching it (thereby moving the
  3347    tooltip).  */
  3348 class EmacsMotionSuppressionView : public BView
  3349 {
  3350   void
  3351   AttachedToWindow (void)
  3352   {
  3353     BView *text_view, *tooltip_view;
  3354 
  3355     /* We know that this view is a child of the text view, whose
  3356        parent is the tooltip view, and that the tooltip view has
  3357        already set its mouse event mask.  */
  3358 
  3359     text_view = Parent ();
  3360 
  3361     if (!text_view)
  3362       return;
  3363 
  3364     tooltip_view = text_view->Parent ();
  3365 
  3366     if (!tooltip_view)
  3367       return;
  3368 
  3369     tooltip_view->SetEventMask (B_KEYBOARD_EVENTS, 0);
  3370   }
  3371 
  3372 public:
  3373   EmacsMotionSuppressionView (void) : BView (BRect (-1, -1, 1, 1),
  3374                                              NULL, 0, 0)
  3375   {
  3376     return;
  3377   }
  3378 };
  3379 
  3380 static int32
  3381 start_running_application (void *data)
  3382 {
  3383   Emacs *app = (Emacs *) data;
  3384 
  3385   haiku_io_init_in_app_thread ();
  3386 
  3387   if (!app->Lock ())
  3388     gui_abort ("Failed to lock application");
  3389 
  3390   app->Run ();
  3391   app->Unlock ();
  3392   return 0;
  3393 }
  3394 
  3395 /* Take BITMAP, a reference to a BBitmap, and return a pointer to its
  3396    data.  */
  3397 void *
  3398 BBitmap_data (void *bitmap)
  3399 {
  3400   return ((BBitmap *) bitmap)->Bits ();
  3401 }
  3402 
  3403 /* Convert bitmap if required, placing the new bitmap in NEW_BITMAP,
  3404    and return non-null if bitmap was successfully converted.  Bitmaps
  3405    should be freed with `BBitmap_free'.  */
  3406 int
  3407 BBitmap_convert (void *_bitmap, void **new_bitmap)
  3408 {
  3409   BBitmap *bitmap = (BBitmap *) _bitmap;
  3410   if (bitmap->ColorSpace () == B_RGBA32)
  3411     return -1;
  3412   BRect bounds = bitmap->Bounds ();
  3413   BBitmap *bmp = new (std::nothrow) BBitmap (bounds, B_RGBA32);
  3414   if (!bmp || bmp->InitCheck () != B_OK)
  3415     {
  3416       if (bmp)
  3417         delete bmp;
  3418       return 0;
  3419     }
  3420   if (bmp->ImportBits (bitmap) != B_OK)
  3421     {
  3422       delete bmp;
  3423       return 0;
  3424     }
  3425   *(BBitmap **) new_bitmap = bmp;
  3426   return 1;
  3427 }
  3428 
  3429 void
  3430 BBitmap_free (void *bitmap)
  3431 {
  3432   delete (BBitmap *) bitmap;
  3433 }
  3434 
  3435 /* Create new bitmap in RGB32 format, or in GRAY1 if MONO_P is
  3436    non-zero.  */
  3437 void *
  3438 BBitmap_new (int width, int height, int mono_p)
  3439 {
  3440   BBitmap *bn = new (std::nothrow) BBitmap (BRect (0, 0, width - 1, height - 1),
  3441                                             mono_p ? B_GRAY1 : B_RGB32);
  3442 
  3443   return bn->InitCheck () == B_OK ? (void *) bn : (void *) (delete bn, NULL);
  3444 }
  3445 
  3446 void
  3447 BBitmap_dimensions (void *bitmap, int *left, int *top,
  3448                     int *right, int *bottom,
  3449                     int32_t *bytes_per_row, int *mono_p)
  3450 {
  3451   BRect rect = ((BBitmap *) bitmap)->Bounds ();
  3452   *left = rect.left;
  3453   *top = rect.top;
  3454   *right = rect.right;
  3455   *bottom = rect.bottom;
  3456 
  3457   *bytes_per_row = ((BBitmap *) bitmap)->BytesPerRow ();
  3458   *mono_p = (((BBitmap *) bitmap)->ColorSpace () == B_GRAY1);
  3459 }
  3460 
  3461 static void
  3462 wait_for_exit_of_app_thread (void)
  3463 {
  3464   status_t ret;
  3465 
  3466   be_app->PostMessage (QUIT_APPLICATION);
  3467   wait_for_thread (app_thread, &ret);
  3468 }
  3469 
  3470 /* Set up an application and return it.  If starting the application
  3471    thread fails, abort Emacs.  */
  3472 void *
  3473 BApplication_setup (void)
  3474 {
  3475   thread_id id;
  3476   Emacs *app;
  3477 
  3478   if (be_app)
  3479     return be_app;
  3480 
  3481   app = new Emacs;
  3482   app->Unlock ();
  3483 
  3484   if ((id = spawn_thread (start_running_application, "Emacs app thread",
  3485                           B_DEFAULT_MEDIA_PRIORITY, app)) < 0)
  3486     gui_abort ("spawn_thread failed");
  3487 
  3488   resume_thread (id);
  3489   app_thread = id;
  3490 
  3491   atexit (wait_for_exit_of_app_thread);
  3492   return app;
  3493 }
  3494 
  3495 /* Set up and return a window with its view put in VIEW.  */
  3496 void *
  3497 BWindow_new (void **view)
  3498 {
  3499   BWindow *window;
  3500   BView *vw;
  3501 
  3502   window = new (std::nothrow) EmacsWindow;
  3503   if (!window)
  3504     {
  3505       *view = NULL;
  3506       return window;
  3507     }
  3508 
  3509   vw = new (std::nothrow) EmacsView;
  3510   if (!vw)
  3511     {
  3512       *view = NULL;
  3513       window->LockLooper ();
  3514       window->Quit ();
  3515       return NULL;
  3516     }
  3517 
  3518   /* Windows are created locked by the current thread, but calling
  3519      Show for the first time causes them to be unlocked.  To avoid a
  3520      deadlock when a frame is created invisible in one thread, and
  3521      another thread later tries to lock it, the window is unlocked
  3522      here, and EmacsShow will lock it manually if it's being shown for
  3523      the first time.  */
  3524   window->UnlockLooper ();
  3525   window->AddChild (vw);
  3526   *view = vw;
  3527   return window;
  3528 }
  3529 
  3530 void
  3531 BWindow_quit (void *window)
  3532 {
  3533   BWindow *w = (BWindow *) window;
  3534 
  3535   w->LockLooper ();
  3536   w->Quit ();
  3537 }
  3538 
  3539 /* Set WINDOW's offset to X, Y.  */
  3540 void
  3541 BWindow_set_offset (void *window, int x, int y)
  3542 {
  3543   BWindow *wn = (BWindow *) window;
  3544   EmacsWindow *w = dynamic_cast<EmacsWindow *> (wn);
  3545   if (w)
  3546     {
  3547       if (!w->LockLooper ())
  3548         gui_abort ("Failed to lock window looper setting offset");
  3549       w->EmacsMoveTo (x, y);
  3550       w->UnlockLooper ();
  3551     }
  3552   else
  3553     wn->MoveTo (x, y);
  3554 }
  3555 
  3556 void
  3557 BWindow_dimensions (void *window, int *width, int *height)
  3558 {
  3559   BWindow *w = (BWindow *) window;
  3560   BRect frame = w->Frame ();
  3561 
  3562   *width = BE_RECT_WIDTH (frame);
  3563   *height = BE_RECT_HEIGHT (frame);
  3564 }
  3565 
  3566 /* Iconify WINDOW.  */
  3567 void
  3568 BWindow_iconify (void *window)
  3569 {
  3570   if (((BWindow *) window)->IsHidden ())
  3571     BWindow_set_visible (window, true);
  3572   ((BWindow *) window)->Minimize (true);
  3573 }
  3574 
  3575 /* Show or hide WINDOW.  */
  3576 void
  3577 BWindow_set_visible (void *window, int visible_p)
  3578 {
  3579   EmacsWindow *win = (EmacsWindow *) window;
  3580   if (visible_p)
  3581     {
  3582       if (win->IsMinimized ())
  3583         win->Minimize (false);
  3584       win->EmacsShow ();
  3585     }
  3586   else if (!win->IsHidden ())
  3587     {
  3588       if (win->IsMinimized ())
  3589         win->Minimize (false);
  3590       win->EmacsHide ();
  3591     }
  3592 }
  3593 
  3594 /* Change the title of WINDOW to the multibyte string TITLE.  */
  3595 void
  3596 BWindow_retitle (void *window, const char *title)
  3597 {
  3598   ((BWindow *) window)->SetTitle (title);
  3599 }
  3600 
  3601 /* Resize WINDOW to WIDTH by HEIGHT.  */
  3602 void
  3603 BWindow_resize (void *window, int width, int height)
  3604 {
  3605   ((BWindow *) window)->ResizeTo (width - 1, height - 1);
  3606 }
  3607 
  3608 /* Activate WINDOW, making it the subject of keyboard focus and
  3609    bringing it to the front of the screen.  */
  3610 void
  3611 BWindow_activate (void *window)
  3612 {
  3613   ((BWindow *) window)->Activate ();
  3614 }
  3615 
  3616 /* Return the pixel dimensions of the main screen in WIDTH and
  3617    HEIGHT.  */
  3618 void
  3619 be_get_screen_dimensions (int *width, int *height)
  3620 {
  3621   BScreen screen;
  3622   BRect frame;
  3623 
  3624   if (!screen.IsValid ())
  3625     gui_abort ("Invalid screen");
  3626 
  3627   frame = screen.Frame ();
  3628 
  3629   *width = BE_RECT_WIDTH (frame);
  3630   *height = BE_RECT_HEIGHT (frame);
  3631 }
  3632 
  3633 /* Resize VIEW to WIDTH, HEIGHT.  */
  3634 void
  3635 BView_resize_to (void *view, int width, int height)
  3636 {
  3637   EmacsView *vw = (EmacsView *) view;
  3638   if (!vw->LockLooper ())
  3639     gui_abort ("Failed to lock view for resize");
  3640   vw->ResizeTo (width, height);
  3641   vw->AfterResize ();
  3642   vw->UnlockLooper ();
  3643 }
  3644 
  3645 void
  3646 be_delete_cursor (void *cursor)
  3647 {
  3648   if (cursor)
  3649     delete (BCursor *) cursor;
  3650 }
  3651 
  3652 void *
  3653 be_create_cursor_from_id (int id)
  3654 {
  3655   return new BCursor ((enum BCursorID) id);
  3656 }
  3657 
  3658 void
  3659 BView_set_view_cursor (void *view, void *cursor)
  3660 {
  3661   BView *v = (BView *) view;
  3662 
  3663   if (!v->LockLooper ())
  3664     gui_abort ("Failed to lock view setting cursor");
  3665   v->SetViewCursor ((BCursor *) cursor);
  3666   v->UnlockLooper ();
  3667 }
  3668 
  3669 void
  3670 BWindow_Flush (void *window)
  3671 {
  3672   ((BWindow *) window)->Flush ();
  3673 }
  3674 
  3675 /* Make a scrollbar, attach it to VIEW's window, and return it.  */
  3676 void *
  3677 be_make_scroll_bar_for_view (void *view, int horizontal_p,
  3678                              int x, int y, int x1, int y1)
  3679 {
  3680   EmacsScrollBar *scroll_bar;
  3681   BView *vw = (BView *) view;
  3682 
  3683   if (!vw->LockLooper ())
  3684     gui_abort ("Failed to lock scrollbar owner");
  3685 
  3686   scroll_bar = new EmacsScrollBar (x, y, x1, y1, horizontal_p,
  3687                                    (EmacsView *) vw);
  3688 
  3689   vw->AddChild (scroll_bar);
  3690   vw->UnlockLooper ();
  3691 
  3692   return scroll_bar;
  3693 }
  3694 
  3695 void
  3696 BScrollBar_delete (void *sb)
  3697 {
  3698   BView *view = (BView *) sb;
  3699   BView *pr = view->Parent ();
  3700 
  3701   if (!pr->LockLooper ())
  3702     gui_abort ("Failed to lock scrollbar parent");
  3703   pr->RemoveChild (view);
  3704   pr->UnlockLooper ();
  3705 
  3706   delete (EmacsScrollBar *) sb;
  3707 }
  3708 
  3709 void
  3710 BView_move_frame (void *view, int x, int y, int x1, int y1)
  3711 {
  3712   BView *vw = (BView *) view;
  3713 
  3714   if (!vw->LockLooper ())
  3715     gui_abort ("Failed to lock view moving frame");
  3716   vw->MoveTo (x, y);
  3717   vw->ResizeTo (x1 - x, y1 - y);
  3718   vw->UnlockLooper ();
  3719 }
  3720 
  3721 /* DRAGGING can either be 0 (which means to update everything), 1
  3722    (which means to update nothing), or -1 (which means to update only
  3723    the thumb size and range).  */
  3724 
  3725 void
  3726 BView_scroll_bar_update (void *sb, int portion, int whole, int position,
  3727                          int dragging, bool can_overscroll)
  3728 {
  3729   BScrollBar *bar = (BScrollBar *) sb;
  3730   BMessage msg = BMessage (SCROLL_BAR_UPDATE);
  3731   BMessenger mr = BMessenger (bar);
  3732   msg.AddInt32 ("emacs:range", whole);
  3733   msg.AddInt32 ("emacs:units", position);
  3734   msg.AddInt32 ("emacs:portion", portion);
  3735   msg.AddInt32 ("emacs:dragging", dragging);
  3736   msg.AddBool ("emacs:overscroll", can_overscroll);
  3737 
  3738   mr.SendMessage (&msg);
  3739 }
  3740 
  3741 /* Return the default scrollbar size.  */
  3742 int
  3743 BScrollBar_default_size (int horizontal_p)
  3744 {
  3745   return be_control_look->GetScrollBarWidth (horizontal_p
  3746                                              ? B_HORIZONTAL
  3747                                              : B_VERTICAL);
  3748 }
  3749 
  3750 /* Invalidate VIEW, causing it to be drawn again.  */
  3751 void
  3752 BView_invalidate (void *view)
  3753 {
  3754   BView *vw = (BView *) view;
  3755   if (!vw->LockLooper ())
  3756     gui_abort ("Couldn't lock view while invalidating it");
  3757   vw->Invalidate ();
  3758   vw->UnlockLooper ();
  3759 }
  3760 
  3761 /* Lock VIEW in preparation for drawing operations.  This should be
  3762    called before any attempt to draw onto VIEW or to lock it for Cairo
  3763    drawing.  `BView_draw_unlock' should be called afterwards.
  3764 
  3765    If any drawing is going to take place, INVALID_REGION should be
  3766    true, and X, Y, WIDTH, HEIGHT should specify a rectangle in which
  3767    the drawing will take place.  */
  3768 void
  3769 BView_draw_lock (void *view, bool invalidate_region,
  3770                  int x, int y, int width, int height)
  3771 {
  3772   EmacsView *vw = (EmacsView *) view;
  3773   if (vw->looper_locked_count)
  3774     {
  3775       vw->looper_locked_count++;
  3776 
  3777       if (invalidate_region && vw->offscreen_draw_view)
  3778         vw->invalid_region.Include (BRect (x, y, x + width - 1,
  3779                                            y + height - 1));
  3780       return;
  3781     }
  3782   BView *v = (BView *) find_appropriate_view_for_draw (vw);
  3783   if (v != vw)
  3784     {
  3785       if (!vw->offscreen_draw_bitmap_1->Lock ())
  3786         gui_abort ("Failed to lock offscreen bitmap while acquiring draw lock");
  3787     }
  3788   else if (!v->LockLooper ())
  3789     gui_abort ("Failed to lock draw view while acquiring draw lock");
  3790 
  3791   if (v != vw && !vw->LockLooper ())
  3792     gui_abort ("Failed to lock view while acquiring draw lock");
  3793 
  3794   if (invalidate_region && vw->offscreen_draw_view)
  3795     vw->invalid_region.Include (BRect (x, y, x + width - 1,
  3796                                        y + height - 1));
  3797   vw->looper_locked_count++;
  3798 }
  3799 
  3800 void
  3801 BView_invalidate_region (void *view, int x, int y, int width, int height)
  3802 {
  3803   EmacsView *vw = (EmacsView *) view;
  3804 
  3805   if (vw->offscreen_draw_view)
  3806     vw->invalid_region.Include (BRect (x, y, x + width - 1,
  3807                                        y + height - 1));
  3808 }
  3809 
  3810 void
  3811 BView_draw_unlock (void *view)
  3812 {
  3813   EmacsView *vw = (EmacsView *) view;
  3814   if (--vw->looper_locked_count)
  3815     return;
  3816 
  3817   BView *v = (BView *) find_appropriate_view_for_draw (view);
  3818   if (v == vw)
  3819     vw->UnlockLooper ();
  3820   else
  3821     {
  3822       vw->offscreen_draw_bitmap_1->Unlock ();
  3823       vw->UnlockLooper ();
  3824     }
  3825 }
  3826 
  3827 void
  3828 BWindow_center_on_screen (void *window)
  3829 {
  3830   BWindow *w = (BWindow *) window;
  3831   w->CenterOnScreen ();
  3832 }
  3833 
  3834 /* Import fringe bitmap (short array, low bit rightmost) BITS into
  3835    BITMAP using the B_GRAY1 colorspace.  */
  3836 void
  3837 BBitmap_import_fringe_bitmap (void *bitmap, unsigned short *bits, int wd, int h)
  3838 {
  3839   BBitmap *bmp = (BBitmap *) bitmap;
  3840   unsigned char *data = (unsigned char *) bmp->Bits ();
  3841   int i;
  3842 
  3843   for (i = 0; i < h; i++)
  3844     {
  3845       if (wd <= 8)
  3846         data[0] = bits[i] & 0xff;
  3847       else
  3848         {
  3849           data[1] = bits[i] & 0xff;
  3850           data[0] = bits[i] >> 8;
  3851         }
  3852 
  3853       data += bmp->BytesPerRow ();
  3854     }
  3855 }
  3856 
  3857 /* Make a scrollbar at X, Y known to the view VIEW.  */
  3858 void
  3859 BView_publish_scroll_bar (void *view, int x, int y, int width, int height)
  3860 {
  3861   EmacsView *vw = (EmacsView *) view;
  3862   if (vw->LockLooper ())
  3863     {
  3864       vw->sb_region.Include (BRect (x, y, x - 1 + width,
  3865                                     y - 1 + height));
  3866       vw->UnlockLooper ();
  3867     }
  3868 }
  3869 
  3870 void
  3871 BView_forget_scroll_bar (void *view, int x, int y, int width, int height)
  3872 {
  3873   EmacsView *vw = (EmacsView *) view;
  3874   if (vw->LockLooper ())
  3875     {
  3876       vw->sb_region.Exclude (BRect (x, y, x - 1 + width,
  3877                                     y - 1 + height));
  3878       vw->UnlockLooper ();
  3879     }
  3880 }
  3881 
  3882 bool
  3883 BView_inside_scroll_bar (void *view, int x, int y)
  3884 {
  3885   EmacsView *vw = (EmacsView *) view;
  3886   bool val;
  3887 
  3888   if (vw->LockLooper ())
  3889     {
  3890       val = vw->sb_region.Contains (BPoint (x, y));
  3891       vw->UnlockLooper ();
  3892     }
  3893   else
  3894     val = false;
  3895 
  3896   return val;
  3897 }
  3898 
  3899 void
  3900 BView_get_mouse (void *view, int *x, int *y)
  3901 {
  3902   BPoint l;
  3903   BView *vw = (BView *) view;
  3904   if (!vw->LockLooper ())
  3905     gui_abort ("Failed to lock view in BView_get_mouse");
  3906   vw->GetMouse (&l, NULL, 1);
  3907   vw->UnlockLooper ();
  3908 
  3909   *x = std::lrint (l.x);
  3910   *y = std::lrint (l.y);
  3911 }
  3912 
  3913 /* Perform an in-place conversion of X and Y from VIEW's coordinate
  3914    system to its screen's coordinate system.  */
  3915 void
  3916 BView_convert_to_screen (void *view, int *x, int *y)
  3917 {
  3918   BPoint l = BPoint (*x, *y);
  3919   BView *vw = (BView *) view;
  3920   if (!vw->LockLooper ())
  3921     gui_abort ("Failed to lock view in convert_to_screen");
  3922   vw->ConvertToScreen (&l);
  3923   vw->UnlockLooper ();
  3924 
  3925   *x = std::lrint (l.x);
  3926   *y = std::lrint (l.y);
  3927 }
  3928 
  3929 void
  3930 BView_convert_from_screen (void *view, int *x, int *y)
  3931 {
  3932   BPoint l = BPoint (*x, *y);
  3933   BView *vw = (BView *) view;
  3934   if (!vw->LockLooper ())
  3935     gui_abort ("Failed to lock view in convert_from_screen");
  3936   vw->ConvertFromScreen (&l);
  3937   vw->UnlockLooper ();
  3938 
  3939   *x = std::lrint (l.x);
  3940   *y = std::lrint (l.y);
  3941 }
  3942 
  3943 /* Decorate or undecorate WINDOW depending on DECORATE_P.  */
  3944 void
  3945 BWindow_change_decoration (void *window, int decorate_p)
  3946 {
  3947   EmacsWindow *w = (EmacsWindow *) window;
  3948   if (!w->LockLooper ())
  3949     gui_abort ("Failed to lock window while changing its decorations");
  3950 
  3951   if (!w->override_redirect_p)
  3952     {
  3953       if (decorate_p)
  3954         w->SetLook (B_TITLED_WINDOW_LOOK);
  3955       else
  3956         w->SetLook (B_NO_BORDER_WINDOW_LOOK);
  3957     }
  3958   else
  3959     {
  3960       if (decorate_p)
  3961         w->pre_override_redirect_look = B_TITLED_WINDOW_LOOK;
  3962       else
  3963         w->pre_override_redirect_look = B_NO_BORDER_WINDOW_LOOK;
  3964     }
  3965   w->UnlockLooper ();
  3966 }
  3967 
  3968 /* Decorate WINDOW appropriately for use as a tooltip.  */
  3969 void
  3970 BWindow_set_tooltip_decoration (void *window)
  3971 {
  3972   EmacsWindow *w = (EmacsWindow *) window;
  3973   if (!w->LockLooper ())
  3974     gui_abort ("Failed to lock window while setting ttip decoration");
  3975   w->tooltip_p = true;
  3976   w->RecomputeFeel ();
  3977   w->SetLook (B_BORDERED_WINDOW_LOOK);
  3978   w->SetFlags (B_NOT_ZOOMABLE
  3979                | B_NOT_MINIMIZABLE
  3980                | B_AVOID_FRONT
  3981                | B_AVOID_FOCUS);
  3982   w->UnlockLooper ();
  3983 }
  3984 
  3985 /* Set B_AVOID_FOCUS on WINDOW if AVOID_FOCUS_P is non-nil, or clear
  3986    it otherwise.  */
  3987 void
  3988 BWindow_set_avoid_focus (void *window, int avoid_focus_p)
  3989 {
  3990   BWindow *w = (BWindow *) window;
  3991   if (!w->LockLooper ())
  3992     gui_abort ("Failed to lock window while setting avoid focus");
  3993 
  3994   if (!avoid_focus_p)
  3995     w->SetFlags (w->Flags () & ~B_AVOID_FOCUS);
  3996   else
  3997     w->SetFlags (w->Flags () | B_AVOID_FOCUS);
  3998   w->UnlockLooper ();
  3999 }
  4000 
  4001 void
  4002 BView_emacs_delete (void *view)
  4003 {
  4004   EmacsView *vw = (EmacsView *) view;
  4005   if (!vw->LockLooper ())
  4006     gui_abort ("Failed to lock view while deleting it");
  4007   vw->RemoveSelf ();
  4008   delete vw;
  4009 }
  4010 
  4011 /* Create a popup menu.  */
  4012 void *
  4013 BPopUpMenu_new (const char *name)
  4014 {
  4015   BPopUpMenu *menu = new BPopUpMenu (name);
  4016 
  4017   menu->SetRadioMode (0);
  4018   return menu;
  4019 }
  4020 
  4021 /* Add a title item to MENU.  These items cannot be highlighted or
  4022    triggered, and their labels will display as bold text.  */
  4023 void
  4024 BMenu_add_title (void *menu, const char *text)
  4025 {
  4026   BMenu *be_menu = (BMenu *) menu;
  4027   EmacsTitleMenuItem *it;
  4028 
  4029   it = new EmacsTitleMenuItem (text);
  4030   be_menu->AddItem (it);
  4031 }
  4032 
  4033 /* Add an item to the menu MENU.  */
  4034 void
  4035 BMenu_add_item (void *menu, const char *label, void *ptr, bool enabled_p,
  4036                 bool marked_p, bool mbar_p, void *mbw_ptr, const char *key,
  4037                 const char *help)
  4038 {
  4039   BMenu *m = (BMenu *) menu;
  4040   BMessage *msg;
  4041   if (ptr)
  4042     msg = new BMessage ();
  4043   EmacsMenuItem *it = new EmacsMenuItem (key, label, help, ptr ? msg : NULL);
  4044   it->SetTarget (m->Window ());
  4045   it->SetEnabled (enabled_p);
  4046   it->SetMarked (marked_p);
  4047   if (mbar_p)
  4048     {
  4049       it->menu_bar_id = (intptr_t) ptr;
  4050       it->wind_ptr = mbw_ptr;
  4051     }
  4052   it->menu_ptr = ptr;
  4053   if (ptr)
  4054     msg->AddPointer ("menuptr", ptr);
  4055   m->AddItem (it);
  4056 }
  4057 
  4058 /* Add a separator to the menu MENU.  */
  4059 void
  4060 BMenu_add_separator (void *menu)
  4061 {
  4062   BMenu *m = (BMenu *) menu;
  4063 
  4064   m->AddSeparatorItem ();
  4065 }
  4066 
  4067 /* Create a submenu and attach it to MENU.  */
  4068 void *
  4069 BMenu_new_submenu (void *menu, const char *label, bool enabled_p)
  4070 {
  4071   BMenu *m = (BMenu *) menu;
  4072   BMenu *mn = new BMenu (label, B_ITEMS_IN_COLUMN);
  4073   mn->SetRadioMode (0);
  4074   BMenuItem *i = new BMenuItem (mn);
  4075   i->SetEnabled (enabled_p);
  4076   m->AddItem (i);
  4077   return mn;
  4078 }
  4079 
  4080 /* Create a submenu that notifies Emacs upon opening.  */
  4081 void *
  4082 BMenu_new_menu_bar_submenu (void *menu, const char *label)
  4083 {
  4084   BMenu *m = (BMenu *) menu;
  4085   BMenu *mn = new BMenu (label, B_ITEMS_IN_COLUMN);
  4086   mn->SetRadioMode (0);
  4087   BMenuItem *i = new BMenuItem (mn);
  4088   i->SetEnabled (1);
  4089   m->AddItem (i);
  4090   return mn;
  4091 }
  4092 
  4093 /* Run MENU, waiting for it to close, and return a pointer to the
  4094    data of the selected item (if one exists), or NULL.  X, Y should
  4095    be in the screen coordinate system.  */
  4096 void *
  4097 BMenu_run (void *menu, int x, int y,
  4098            void (*run_help_callback) (void *, void *),
  4099            void (*block_input_function) (void),
  4100            void (*unblock_input_function) (void),
  4101            struct timespec (*process_pending_signals_function) (void),
  4102            void *run_help_callback_data)
  4103 {
  4104   BPopUpMenu *mn = (BPopUpMenu *) menu;
  4105   enum haiku_event_type type;
  4106   void *buf;
  4107   void *ptr = NULL;
  4108   struct be_popup_menu_data data;
  4109   struct object_wait_info infos[3];
  4110   struct haiku_menu_bar_help_event *event;
  4111   BMessage *msg;
  4112   ssize_t stat;
  4113   struct timespec next_time;
  4114   bigtime_t timeout;
  4115 
  4116   block_input_function ();
  4117   port_popup_menu_to_emacs = create_port (1800, "popup menu port");
  4118   data.x = x;
  4119   data.y = y;
  4120   data.menu = mn;
  4121   unblock_input_function ();
  4122 
  4123   if (port_popup_menu_to_emacs < B_OK)
  4124     return NULL;
  4125 
  4126   block_input_function ();
  4127   mn->SetRadioMode (0);
  4128   buf = alloca (200);
  4129 
  4130   infos[0].object = port_popup_menu_to_emacs;
  4131   infos[0].type = B_OBJECT_TYPE_PORT;
  4132   infos[0].events = B_EVENT_READ;
  4133 
  4134   infos[1].object = spawn_thread (be_popup_menu_thread_entry,
  4135                                   "Menu tracker", B_DEFAULT_MEDIA_PRIORITY,
  4136                                   (void *) &data);
  4137   infos[1].type = B_OBJECT_TYPE_THREAD;
  4138   infos[1].events = B_EVENT_INVALID;
  4139 
  4140   infos[2].object = port_application_to_emacs;
  4141   infos[2].type = B_OBJECT_TYPE_PORT;
  4142   infos[2].events = B_EVENT_READ;
  4143   unblock_input_function ();
  4144 
  4145   if (infos[1].object < B_OK)
  4146     {
  4147       block_input_function ();
  4148       delete_port (port_popup_menu_to_emacs);
  4149       unblock_input_function ();
  4150       return NULL;
  4151     }
  4152 
  4153   block_input_function ();
  4154   resume_thread (infos[1].object);
  4155   unblock_input_function ();
  4156 
  4157   while (true)
  4158     {
  4159       next_time = process_pending_signals_function ();
  4160 
  4161       if (next_time.tv_nsec < 0)
  4162         timeout = 10000000000;
  4163       else
  4164         timeout = (next_time.tv_sec * 1000000
  4165                    + next_time.tv_nsec / 1000);
  4166 
  4167       if ((stat = wait_for_objects_etc ((object_wait_info *) &infos, 3,
  4168                                         B_RELATIVE_TIMEOUT, timeout)) < B_OK)
  4169         {
  4170           if (stat == B_INTERRUPTED || stat == B_TIMED_OUT
  4171               || stat == B_WOULD_BLOCK)
  4172             continue;
  4173           else
  4174             gui_abort ("Failed to wait for popup");
  4175         }
  4176 
  4177       if (infos[0].events & B_EVENT_READ)
  4178         {
  4179           while (!haiku_read_with_timeout (&type, buf, 200, 0, true))
  4180             {
  4181               switch (type)
  4182                 {
  4183                 case MENU_BAR_HELP_EVENT:
  4184                   event = (struct haiku_menu_bar_help_event *) buf;
  4185                   run_help_callback (event->highlight_p
  4186                                      ? event->data
  4187                                      : NULL, run_help_callback_data);
  4188                   break;
  4189                 default:
  4190                   gui_abort ("Unknown popup menu event");
  4191                 }
  4192             }
  4193         }
  4194 
  4195       if (infos[1].events & B_EVENT_INVALID)
  4196         {
  4197           block_input_function ();
  4198           msg = (BMessage *) popup_track_message;
  4199           if (popup_track_message)
  4200             ptr = (void *) msg->GetPointer ("menuptr");
  4201 
  4202           delete_port (port_popup_menu_to_emacs);
  4203           unblock_input_function ();
  4204           return ptr;
  4205         }
  4206 
  4207       infos[0].events = B_EVENT_READ;
  4208       infos[1].events = B_EVENT_INVALID;
  4209       infos[2].events = B_EVENT_READ;
  4210     }
  4211 }
  4212 
  4213 /* Delete the entire menu hierarchy of MENU, and then delete MENU
  4214    itself.  */
  4215 void
  4216 BPopUpMenu_delete (void *menu)
  4217 {
  4218   delete (BPopUpMenu *) menu;
  4219 }
  4220 
  4221 /* Create a menubar, attach it to VIEW, and return it.  */
  4222 void *
  4223 BMenuBar_new (void *view)
  4224 {
  4225   BView *vw = (BView *) view;
  4226   EmacsMenuBar *bar = new EmacsMenuBar ();
  4227 
  4228   if (!vw->LockLooper ())
  4229     gui_abort ("Failed to lock menu bar parent");
  4230   vw->AddChild ((BView *) bar);
  4231   vw->UnlockLooper ();
  4232 
  4233   return bar;
  4234 }
  4235 
  4236 /* Delete MENUBAR along with all subitems. */
  4237 void
  4238 BMenuBar_delete (void *menubar)
  4239 {
  4240   BView *vw = (BView *) menubar;
  4241   BView *p = vw->Parent ();
  4242   EmacsWindow *window = (EmacsWindow *) p->Window ();
  4243 
  4244   if (!p->LockLooper ())
  4245     gui_abort ("Failed to lock menu bar parent while removing menubar");
  4246   window->SetKeyMenuBar (NULL);
  4247   /* MenusEnded isn't called if the menu bar is destroyed
  4248      before it closes.  */
  4249   window->menu_bar_active_p = false;
  4250   vw->RemoveSelf ();
  4251   p->UnlockLooper ();
  4252   delete vw;
  4253 }
  4254 
  4255 /* Delete all items from MENU.  */
  4256 void
  4257 BMenu_delete_all (void *menu)
  4258 {
  4259   BMenu *mn = (BMenu *) menu;
  4260   mn->RemoveItems (0, mn->CountItems (), true);
  4261 }
  4262 
  4263 /* Delete COUNT items from MENU starting from START.  */
  4264 void
  4265 BMenu_delete_from (void *menu, int start, int count)
  4266 {
  4267   BMenu *mn = (BMenu *) menu;
  4268   mn->RemoveItems (start, count, true);
  4269 }
  4270 
  4271 /* Count items in menu MENU.  */
  4272 int
  4273 BMenu_count_items (void *menu)
  4274 {
  4275   return ((BMenu *) menu)->CountItems ();
  4276 }
  4277 
  4278 /* Find the item in MENU at IDX.  */
  4279 void *
  4280 BMenu_item_at (void *menu, int idx)
  4281 {
  4282   return ((BMenu *) menu)->ItemAt (idx);
  4283 }
  4284 
  4285 /* Set ITEM's label to LABEL.  */
  4286 void
  4287 BMenu_item_set_label (void *item, const char *label)
  4288 {
  4289   ((BMenuItem *) item)->SetLabel (label);
  4290 }
  4291 
  4292 /* Get ITEM's menu.  */
  4293 void *
  4294 BMenu_item_get_menu (void *item)
  4295 {
  4296   return ((BMenuItem *) item)->Submenu ();
  4297 }
  4298 
  4299 /* Emit a beep noise.  */
  4300 void
  4301 haiku_ring_bell (void)
  4302 {
  4303   beep ();
  4304 }
  4305 
  4306 /* Create a BAlert with TEXT.  */
  4307 void *
  4308 BAlert_new (const char *text, enum haiku_alert_type type)
  4309 {
  4310   return new BAlert (NULL, text, NULL, NULL, NULL, B_WIDTH_AS_USUAL,
  4311                      (enum alert_type) type);
  4312 }
  4313 
  4314 /* Add a button to ALERT and return the button.  */
  4315 void *
  4316 BAlert_add_button (void *alert, const char *text)
  4317 {
  4318   BAlert *al = (BAlert *) alert;
  4319   al->AddButton (text);
  4320   return al->ButtonAt (al->CountButtons () - 1);
  4321 }
  4322 
  4323 /* Make sure the leftmost button is grouped to the left hand side of
  4324    the alert.  */
  4325 void
  4326 BAlert_set_offset_spacing (void *alert)
  4327 {
  4328   BAlert *al = (BAlert *) alert;
  4329 
  4330   al->SetButtonSpacing (B_OFFSET_SPACING);
  4331 }
  4332 
  4333 static int32
  4334 be_alert_thread_entry (void *thread_data)
  4335 {
  4336   BAlert *alert = (BAlert *) thread_data;
  4337   int32 value;
  4338 
  4339   if (alert->LockLooper ())
  4340     value = alert->Go ();
  4341   else
  4342     value = -1;
  4343 
  4344   alert_popup_value = value;
  4345   return 0;
  4346 }
  4347 
  4348 /* Run ALERT, returning the number of the button that was selected,
  4349    or -1 if no button was selected before the alert was closed.  */
  4350 int32
  4351 BAlert_go (void *alert,
  4352            void (*block_input_function) (void),
  4353            void (*unblock_input_function) (void),
  4354            void (*process_pending_signals_function) (void))
  4355 {
  4356   struct object_wait_info infos[2];
  4357   ssize_t stat;
  4358   BAlert *alert_object = (BAlert *) alert;
  4359 
  4360   infos[0].object = port_application_to_emacs;
  4361   infos[0].type = B_OBJECT_TYPE_PORT;
  4362   infos[0].events = B_EVENT_READ;
  4363 
  4364   block_input_function ();
  4365   /* Alerts are created locked, just like other windows.  */
  4366   alert_object->UnlockLooper ();
  4367   infos[1].object = spawn_thread (be_alert_thread_entry,
  4368                                   "Popup tracker",
  4369                                   B_DEFAULT_MEDIA_PRIORITY,
  4370                                   alert);
  4371   infos[1].type = B_OBJECT_TYPE_THREAD;
  4372   infos[1].events = B_EVENT_INVALID;
  4373   unblock_input_function ();
  4374 
  4375   if (infos[1].object < B_OK)
  4376     return -1;
  4377 
  4378   block_input_function ();
  4379   resume_thread (infos[1].object);
  4380   unblock_input_function ();
  4381 
  4382   while (true)
  4383     {
  4384       stat = wait_for_objects ((object_wait_info *) &infos, 2);
  4385 
  4386       if (stat == B_INTERRUPTED)
  4387         continue;
  4388       else if (stat < B_OK)
  4389         gui_abort ("Failed to wait for popup dialog");
  4390 
  4391       if (infos[1].events & B_EVENT_INVALID)
  4392         return alert_popup_value;
  4393 
  4394       if (infos[0].events & B_EVENT_READ)
  4395         process_pending_signals_function ();
  4396 
  4397       infos[0].events = B_EVENT_READ;
  4398       infos[1].events = B_EVENT_INVALID;
  4399     }
  4400 }
  4401 
  4402 /* Enable or disable BUTTON depending on ENABLED_P.  */
  4403 void
  4404 BButton_set_enabled (void *button, int enabled_p)
  4405 {
  4406   ((BButton *) button)->SetEnabled (enabled_p);
  4407 }
  4408 
  4409 /* Set VIEW's tooltip to TOOLTIP.  */
  4410 void
  4411 BView_set_tooltip (void *view, const char *tooltip)
  4412 {
  4413   ((BView *) view)->SetToolTip (tooltip);
  4414 }
  4415 
  4416 /* Set VIEW's tooltip to a sticky tooltip at X by Y.  */
  4417 void
  4418 be_show_sticky_tooltip (void *view, const char *tooltip_text,
  4419                         int x, int y)
  4420 {
  4421   BToolTip *tooltip;
  4422   BView *vw, *tooltip_view;
  4423   BPoint point;
  4424 
  4425   vw = (BView *) view;
  4426 
  4427   if (!vw->LockLooper ())
  4428     gui_abort ("Failed to lock view while showing sticky tooltip");
  4429 
  4430   vw->SetToolTip ((const char *) NULL);
  4431 
  4432   /* If the tooltip text is empty, then a tooltip object won't be
  4433      created by SetToolTip.  */
  4434   if (tooltip_text[0] == '\0')
  4435     tooltip_text = " ";
  4436 
  4437   vw->SetToolTip (tooltip_text);
  4438 
  4439   tooltip = vw->ToolTip ();
  4440 
  4441   vw->GetMouse (&point, NULL, 1);
  4442   point.x -= x;
  4443   point.y -= y;
  4444 
  4445   point.x = -point.x;
  4446   point.y = -point.y;
  4447 
  4448   /* We don't have to make the tooltip sticky since not receiving
  4449      mouse movement is enough to prevent it from being hidden.  */
  4450   tooltip->SetMouseRelativeLocation (point);
  4451 
  4452   /* Prevent the tooltip from moving in response to mouse
  4453      movement.  */
  4454   tooltip_view = tooltip->View ();
  4455 
  4456   if (tooltip_view)
  4457     tooltip_view->AddChild (new EmacsMotionSuppressionView);
  4458 
  4459   vw->ShowToolTip (tooltip);
  4460   vw->UnlockLooper ();
  4461 }
  4462 
  4463 /* Delete ALERT.  */
  4464 void
  4465 BAlert_delete (void *alert)
  4466 {
  4467   delete (BAlert *) alert;
  4468 }
  4469 
  4470 /* Place the resolution of the monitor in DPI in X_OUT and Y_OUT.  */
  4471 void
  4472 be_get_display_resolution (double *x_out, double *y_out)
  4473 {
  4474   BScreen s (B_MAIN_SCREEN_ID);
  4475   monitor_info i;
  4476   double x_inches, y_inches;
  4477   BRect frame;
  4478 
  4479   if (!s.IsValid ())
  4480     gui_abort ("Invalid screen for resolution checks");
  4481 
  4482   if (s.GetMonitorInfo (&i) == B_OK)
  4483     {
  4484       frame = s.Frame ();
  4485 
  4486       x_inches = (double) i.width * 25.4;
  4487       y_inches = (double) i.height * 25.4;
  4488 
  4489       *x_out = (double) BE_RECT_WIDTH (frame) / x_inches;
  4490       *y_out = (double) BE_RECT_HEIGHT (frame) / y_inches;
  4491       return;
  4492     }
  4493 
  4494   *x_out = 72.0;
  4495   *y_out = 72.0;
  4496 }
  4497 
  4498 /* Add WINDOW to OTHER_WINDOW's subset and parent it to
  4499    OTHER_WINDOW.  */
  4500 void
  4501 EmacsWindow_parent_to (void *window, void *other_window)
  4502 {
  4503   EmacsWindow *w = (EmacsWindow *) window;
  4504   if (!w->LockLooper ())
  4505     gui_abort ("Failed to lock window while parenting");
  4506   w->ParentTo ((EmacsWindow *) other_window);
  4507   w->UnlockLooper ();
  4508 }
  4509 
  4510 void
  4511 EmacsWindow_unparent (void *window)
  4512 {
  4513   EmacsWindow *w = (EmacsWindow *) window;
  4514   if (!w->LockLooper ())
  4515     gui_abort ("Failed to lock window while unparenting");
  4516   w->UnparentAndUnlink ();
  4517   w->UnlockLooper ();
  4518 }
  4519 
  4520 /* Place text describing the current version of Haiku in VERSION,
  4521    which should be a buffer LEN bytes wide.  */
  4522 void
  4523 be_get_version_string (char *version, int len)
  4524 {
  4525   std::strncpy (version, "Unknown Haiku release", len - 1);
  4526   version[len - 1] = '\0';
  4527 
  4528   BPath path;
  4529   if (find_directory (B_BEOS_LIB_DIRECTORY, &path) == B_OK)
  4530     {
  4531       path.Append ("libbe.so");
  4532 
  4533       BAppFileInfo appFileInfo;
  4534       version_info versionInfo;
  4535       BFile file;
  4536       if (file.SetTo (path.Path (), B_READ_ONLY) == B_OK
  4537           && appFileInfo.SetTo (&file) == B_OK
  4538           && appFileInfo.GetVersionInfo (&versionInfo,
  4539                                          B_APP_VERSION_KIND) == B_OK
  4540           && versionInfo.short_info[0] != '\0')
  4541         {
  4542           std::strncpy (version, versionInfo.short_info, len - 1);
  4543           version[len - 1] = '\0';
  4544         }
  4545     }
  4546 }
  4547 
  4548 /* Return the amount of color planes in the current display.  */
  4549 int
  4550 be_get_display_planes (void)
  4551 {
  4552   color_space space = dpy_color_space;
  4553   BScreen screen;
  4554 
  4555   if (space == B_NO_COLOR_SPACE)
  4556     {
  4557       if (!screen.IsValid ())
  4558         gui_abort ("Invalid screen");
  4559 
  4560       space = dpy_color_space = screen.ColorSpace ();
  4561     }
  4562 
  4563   switch (space)
  4564     {
  4565     case B_RGB32:
  4566     case B_RGB24:
  4567       return 24;
  4568     case B_RGB16:
  4569       return 16;
  4570     case B_RGB15:
  4571       return 15;
  4572     case B_CMAP8:
  4573     case B_GRAY8:
  4574       return 8;
  4575     case B_GRAY1:
  4576       return 1;
  4577 
  4578     default:
  4579       gui_abort ("Bad colorspace for screen");
  4580     }
  4581 
  4582   /* https://www.haiku-os.org/docs/api/classBScreen.html
  4583      says a valid screen can't be anything else.  */
  4584   return -1;
  4585 }
  4586 
  4587 /* Return the amount of colors the display can handle.  */
  4588 int
  4589 be_get_display_color_cells (void)
  4590 {
  4591   BScreen screen;
  4592   color_space space = dpy_color_space;
  4593 
  4594   if (space == B_NO_COLOR_SPACE)
  4595     {
  4596       if (!screen.IsValid ())
  4597         gui_abort ("Invalid screen");
  4598 
  4599       space = dpy_color_space = screen.ColorSpace ();
  4600     }
  4601 
  4602   switch (space)
  4603     {
  4604     case B_RGB32:
  4605     case B_RGB24:
  4606       return 16777216;
  4607     case B_RGB16:
  4608       return 65536;
  4609     case B_RGB15:
  4610       return 32768;
  4611     case B_CMAP8:
  4612     case B_GRAY8:
  4613       return 256;
  4614     case B_GRAY1:
  4615       return 2;
  4616 
  4617     default:
  4618       gui_abort ("Bad colorspace for screen");
  4619     }
  4620 
  4621   return -1;
  4622 }
  4623 
  4624 /* Return whether or not the current display is only capable of
  4625    producing grayscale colors.  */
  4626 bool
  4627 be_is_display_grayscale (void)
  4628 {
  4629   BScreen screen;
  4630   color_space space = dpy_color_space;
  4631 
  4632   if (space == B_NO_COLOR_SPACE)
  4633     {
  4634       if (!screen.IsValid ())
  4635         gui_abort ("Invalid screen");
  4636 
  4637       space = dpy_color_space = screen.ColorSpace ();
  4638     }
  4639 
  4640   return space == B_GRAY8 || space == B_GRAY1;
  4641 }
  4642 
  4643 /* Warp the pointer to X by Y.  */
  4644 void
  4645 be_warp_pointer (int x, int y)
  4646 {
  4647   /* We're not supposed to use the following function without a
  4648      BWindowScreen object, but in Haiku nothing actually prevents us
  4649      from doing so.  */
  4650 
  4651   set_mouse_position (x, y);
  4652 }
  4653 
  4654 /* Update the position of CHILD in WINDOW without actually moving
  4655    it.  */
  4656 void
  4657 EmacsWindow_move_weak_child (void *window, void *child, int xoff, int yoff)
  4658 {
  4659   EmacsWindow *w = (EmacsWindow *) window;
  4660   EmacsWindow *c = (EmacsWindow *) child;
  4661 
  4662   if (!w->LockLooper ())
  4663     gui_abort ("Couldn't lock window for weak move");
  4664   w->MoveChild (c, xoff, yoff, 1);
  4665   w->UnlockLooper ();
  4666 }
  4667 
  4668 /* Find an appropriate view to draw onto.  If VW is double-buffered,
  4669    this will be the view used for double buffering instead of VW
  4670    itself.  */
  4671 void *
  4672 find_appropriate_view_for_draw (void *vw)
  4673 {
  4674   BView *v = (BView *) vw;
  4675   EmacsView *ev = dynamic_cast<EmacsView *>(v);
  4676   if (!ev)
  4677     return v;
  4678 
  4679   return ev->offscreen_draw_view ? ev->offscreen_draw_view : vw;
  4680 }
  4681 
  4682 /* Set up double buffering for VW.  */
  4683 void
  4684 EmacsView_set_up_double_buffering (void *vw)
  4685 {
  4686   EmacsView *view = (EmacsView *) vw;
  4687   if (!view->LockLooper ())
  4688     gui_abort ("Couldn't lock view while setting up double buffering");
  4689   if (view->offscreen_draw_view)
  4690     {
  4691       view->UnlockLooper ();
  4692       return;
  4693     }
  4694   view->SetUpDoubleBuffering ();
  4695   view->UnlockLooper ();
  4696 }
  4697 
  4698 /* Flip and invalidate the view VW.  */
  4699 void
  4700 EmacsView_flip_and_blit (void *vw)
  4701 {
  4702   EmacsView *view = (EmacsView *) vw;
  4703   if (!view->offscreen_draw_view)
  4704     return;
  4705   if (!view->LockLooper ())
  4706     gui_abort ("Couldn't lock view in flip_and_blit");
  4707   view->FlipBuffers ();
  4708   view->UnlockLooper ();
  4709 }
  4710 
  4711 /* Disable double buffering for VW.  */
  4712 void
  4713 EmacsView_disable_double_buffering (void *vw)
  4714 {
  4715   EmacsView *view = (EmacsView *) vw;
  4716   if (!view->LockLooper ())
  4717     gui_abort ("Couldn't lock view tearing down double buffering");
  4718   view->TearDownDoubleBuffering ();
  4719   view->UnlockLooper ();
  4720 }
  4721 
  4722 /* Return non-0 if VW is double-buffered.  */
  4723 int
  4724 EmacsView_double_buffered_p (void *vw)
  4725 {
  4726   EmacsView *view = (EmacsView *) vw;
  4727   if (!view->LockLooper ())
  4728     gui_abort ("Couldn't lock view testing double buffering status");
  4729   int db_p = !!view->offscreen_draw_view;
  4730   view->UnlockLooper ();
  4731   return db_p;
  4732 }
  4733 
  4734 /* Popup a file dialog.  */
  4735 char *
  4736 be_popup_file_dialog (int open_p, const char *default_dir, int must_match_p,
  4737                       int dir_only_p, void *window, const char *save_text,
  4738                       const char *prompt,
  4739                       void (*process_pending_signals_function) (void))
  4740 {
  4741   BWindow *panel_window;
  4742   BEntry path;
  4743   BMessage msg (FILE_PANEL_SELECTION);
  4744   BFilePanel panel (open_p ? B_OPEN_PANEL : B_SAVE_PANEL,
  4745                     NULL, NULL, (dir_only_p
  4746                                  ? B_DIRECTORY_NODE
  4747                                  : B_FILE_NODE | B_DIRECTORY_NODE));
  4748   char *file_name;
  4749   EmacsFilePanelCallbackLooper *looper;
  4750 
  4751   looper = new EmacsFilePanelCallbackLooper;
  4752 
  4753   if (looper->InitCheck () < B_OK)
  4754     {
  4755       delete looper;
  4756       return NULL;
  4757     }
  4758 
  4759   if (default_dir)
  4760     {
  4761       if (path.SetTo (default_dir, 0) != B_OK)
  4762         default_dir = NULL;
  4763     }
  4764 
  4765   panel_window = panel.Window ();
  4766 
  4767   if (default_dir)
  4768     panel.SetPanelDirectory (&path);
  4769 
  4770   if (save_text)
  4771     panel.SetSaveText (save_text);
  4772 
  4773   panel_window->SetTitle (prompt);
  4774   panel_window->SetFeel (B_MODAL_APP_WINDOW_FEEL);
  4775 
  4776   panel.SetHideWhenDone (false);
  4777   panel.SetTarget (BMessenger (looper));
  4778   panel.SetMessage (&msg);
  4779   panel.Show ();
  4780 
  4781   looper->Run ();
  4782   file_name = looper->ReadFileName (process_pending_signals_function);
  4783 
  4784   if (looper->Lock ())
  4785     looper->Quit ();
  4786 
  4787   return file_name;
  4788 }
  4789 
  4790 /* Move the pointer into MBAR and start tracking.  Return whether the
  4791    menu bar was opened correctly.  */
  4792 bool
  4793 BMenuBar_start_tracking (void *mbar)
  4794 {
  4795   EmacsMenuBar *mb = (EmacsMenuBar *) mbar;
  4796   BMessenger messenger (mb);
  4797   BMessage reply;
  4798 
  4799   messenger.SendMessage (SHOW_MENU_BAR, &reply);
  4800 
  4801   return reply.what == BE_MENU_BAR_OPEN;
  4802 }
  4803 
  4804 #ifdef HAVE_NATIVE_IMAGE_API
  4805 int
  4806 be_can_translate_type_to_bitmap_p (const char *mime)
  4807 {
  4808   BTranslatorRoster *r = BTranslatorRoster::Default ();
  4809   translator_id *ids;
  4810   int32 id_len;
  4811 
  4812   if (r->GetAllTranslators (&ids, &id_len) != B_OK)
  4813     return 0;
  4814 
  4815   int found_in = 0;
  4816   int found_out = 0;
  4817 
  4818   for (int i = 0; i < id_len; ++i)
  4819     {
  4820       found_in = 0;
  4821       found_out = 0;
  4822       const translation_format *i_fmts;
  4823       const translation_format *o_fmts;
  4824 
  4825       int32 i_count, o_count;
  4826 
  4827       if (r->GetInputFormats (ids[i], &i_fmts, &i_count) != B_OK)
  4828         continue;
  4829 
  4830       if (r->GetOutputFormats (ids[i], &o_fmts, &o_count) != B_OK)
  4831         continue;
  4832 
  4833       for (int x = 0; x < i_count; ++x)
  4834         {
  4835           if (!strcmp (i_fmts[x].MIME, mime))
  4836             {
  4837               found_in = 1;
  4838               break;
  4839             }
  4840         }
  4841 
  4842       for (int x = 0; x < i_count; ++x)
  4843         {
  4844           if (!strcmp (o_fmts[x].MIME, "image/x-be-bitmap") ||
  4845               !strcmp (o_fmts[x].MIME, "image/x-vnd.Be-bitmap"))
  4846             {
  4847               found_out = 1;
  4848               break;
  4849             }
  4850         }
  4851 
  4852       if (found_in && found_out)
  4853         break;
  4854     }
  4855 
  4856   delete [] ids;
  4857 
  4858   return found_in && found_out;
  4859 }
  4860 
  4861 void *
  4862 be_translate_bitmap_from_file_name (const char *filename)
  4863 {
  4864   BBitmap *bm = BTranslationUtils::GetBitmap (filename);
  4865   return bm;
  4866 }
  4867 
  4868 void *
  4869 be_translate_bitmap_from_memory (const void *buf, size_t bytes)
  4870 {
  4871   BMemoryIO io (buf, bytes);
  4872   BBitmap *bm = BTranslationUtils::GetBitmap (&io);
  4873   return bm;
  4874 }
  4875 #endif
  4876 
  4877 /* Return the size of BITMAP's data, in bytes.  */
  4878 size_t
  4879 BBitmap_bytes_length (void *bitmap)
  4880 {
  4881   BBitmap *bm = (BBitmap *) bitmap;
  4882   return bm->BitsLength ();
  4883 }
  4884 
  4885 /* Show VIEW's tooltip.  */
  4886 void
  4887 BView_show_tooltip (void *view)
  4888 {
  4889   BView *vw = (BView *) view;
  4890   if (vw->LockLooper ())
  4891     {
  4892       vw->ShowToolTip (vw->ToolTip ());
  4893       vw->UnlockLooper ();
  4894     }
  4895 }
  4896 
  4897 
  4898 #ifdef USE_BE_CAIRO
  4899 /* Return VIEW's cairo context.  */
  4900 cairo_t *
  4901 EmacsView_cairo_context (void *view)
  4902 {
  4903   EmacsView *vw = (EmacsView *) view;
  4904   return vw->cr_context;
  4905 }
  4906 
  4907 /* Transfer each clip rectangle in VIEW to the cairo context
  4908    CTX.  */
  4909 void
  4910 BView_cr_dump_clipping (void *view, cairo_t *ctx)
  4911 {
  4912   BView *vw = (BView *) find_appropriate_view_for_draw (view);
  4913   BRegion cr;
  4914   vw->GetClippingRegion (&cr);
  4915 
  4916   for (int i = 0; i < cr.CountRects (); ++i)
  4917     {
  4918       BRect r = cr.RectAt (i);
  4919       cairo_rectangle (ctx, r.left, r.top,
  4920                        BE_RECT_WIDTH (r),
  4921                        BE_RECT_HEIGHT (r));
  4922     }
  4923 
  4924   cairo_clip (ctx);
  4925 }
  4926 
  4927 /* Lock WINDOW in preparation for drawing using Cairo.  */
  4928 void
  4929 EmacsWindow_begin_cr_critical_section (void *window)
  4930 {
  4931   BWindow *w = (BWindow *) window;
  4932   BView *vw = (BView *) w->FindView ("Emacs");
  4933   EmacsView *ev = dynamic_cast <EmacsView *> (vw);
  4934   if (ev && !ev->cr_surface_lock.Lock ())
  4935     gui_abort ("Couldn't lock view cairo surface");
  4936 }
  4937 
  4938 /* Unlock WINDOW in preparation for drawing using Cairo.  */
  4939 void
  4940 EmacsWindow_end_cr_critical_section (void *window)
  4941 {
  4942   BWindow *w = (BWindow *) window;
  4943   BView *vw = (BView *) w->FindView ("Emacs");
  4944   EmacsView *ev = dynamic_cast <EmacsView *> (vw);
  4945   if (ev)
  4946     ev->cr_surface_lock.Unlock ();
  4947 }
  4948 #endif
  4949 
  4950 /* Get the width of STR in the plain font.  */
  4951 int
  4952 be_string_width_with_plain_font (const char *str)
  4953 {
  4954   return be_plain_font->StringWidth (str);
  4955 }
  4956 
  4957 /* Get the ascent + descent of the plain font.  */
  4958 int
  4959 be_plain_font_height (void)
  4960 {
  4961   struct font_height fheight;
  4962   be_plain_font->GetHeight (&fheight);
  4963 
  4964   return fheight.ascent + fheight.descent;
  4965 }
  4966 
  4967 /* Return the number of physical displays connected.  */
  4968 int
  4969 be_get_display_screens (void)
  4970 {
  4971   int count = 1;
  4972   BScreen scr;
  4973 
  4974   if (!scr.IsValid ())
  4975     gui_abort ("Main screen vanished!");
  4976   while (scr.SetToNext () == B_OK && scr.IsValid ())
  4977     ++count;
  4978 
  4979   return count;
  4980 }
  4981 
  4982 /* Set the minimum width the user can resize WINDOW to.  */
  4983 /* Synchronize WINDOW's connection to the App Server.  */
  4984 void
  4985 BWindow_sync (void *window)
  4986 {
  4987   BWindow *w = (BWindow *) window;
  4988 
  4989   if (!w->LockLooper ())
  4990     gui_abort ("Failed to lock window looper for sync");
  4991   w->Sync ();
  4992   w->UnlockLooper ();
  4993 }
  4994 
  4995 /* Set the alignment of WINDOW's dimensions.  */
  4996 void
  4997 BWindow_set_size_alignment (void *window, int align_width, int align_height)
  4998 {
  4999   BWindow *w = (BWindow *) window;
  5000 
  5001   if (!w->LockLooper ())
  5002     gui_abort ("Failed to lock window looper setting alignment");
  5003 #if 0 /* Haiku does not currently implement SetWindowAlignment.  */
  5004   if (w->SetWindowAlignment (B_PIXEL_ALIGNMENT, -1, -1, align_width,
  5005                              align_width, -1, -1, align_height,
  5006                              align_height) != B_NO_ERROR)
  5007     gui_abort ("Invalid pixel alignment");
  5008 #endif
  5009   w->UnlockLooper ();
  5010 }
  5011 
  5012 void
  5013 BWindow_send_behind (void *window, void *other_window)
  5014 {
  5015   BWindow *w = (BWindow *) window;
  5016   BWindow *other = (BWindow *) other_window;
  5017 
  5018   if (!w->LockLooper ())
  5019     gui_abort ("Failed to lock window in order to send it behind another");
  5020   w->SendBehind (other);
  5021   w->UnlockLooper ();
  5022 }
  5023 
  5024 bool
  5025 BWindow_is_active (void *window)
  5026 {
  5027   BWindow *w = (BWindow *) window;
  5028   return w->IsActive ();
  5029 }
  5030 
  5031 bool
  5032 be_use_subpixel_antialiasing (void)
  5033 {
  5034   bool current_subpixel_antialiasing;
  5035 
  5036   if (get_subpixel_antialiasing (&current_subpixel_antialiasing) != B_OK)
  5037     return false;
  5038 
  5039   return current_subpixel_antialiasing;
  5040 }
  5041 
  5042 void
  5043 BWindow_set_override_redirect (void *window, bool override_redirect_p)
  5044 {
  5045   EmacsWindow *w = (EmacsWindow *) window;
  5046 
  5047   if (w->LockLooper ())
  5048     {
  5049       if (override_redirect_p && !w->override_redirect_p)
  5050         {
  5051           w->override_redirect_p = true;
  5052           w->pre_override_redirect_look = w->Look ();
  5053           w->RecomputeFeel ();
  5054           w->SetLook (B_NO_BORDER_WINDOW_LOOK);
  5055           w->pre_override_redirect_workspaces = w->Workspaces ();
  5056           w->SetWorkspaces (B_ALL_WORKSPACES);
  5057         }
  5058       else if (w->override_redirect_p)
  5059         {
  5060           w->override_redirect_p = false;
  5061           w->SetLook (w->pre_override_redirect_look);
  5062           w->RecomputeFeel ();
  5063           w->SetWorkspaces (w->pre_override_redirect_workspaces);
  5064         }
  5065 
  5066       w->UnlockLooper ();
  5067     }
  5068 }
  5069 
  5070 /* Find a resource by the name NAME inside the settings file.  The
  5071    string returned is in UTF-8 encoding, and will stay allocated as
  5072    long as the BApplication (a.k.a display) is alive.  */
  5073 const char *
  5074 be_find_setting (const char *name)
  5075 {
  5076   Emacs *app = (Emacs *) be_app;
  5077   const char *value;
  5078 
  5079   /* Note that this is thread-safe since the constructor of `Emacs'
  5080      runs in the main thread.  */
  5081   if (!app->settings_valid_p)
  5082     return NULL;
  5083 
  5084   if (app->settings.FindString (name, 0, &value) != B_OK)
  5085     return NULL;
  5086 
  5087   return value;
  5088 }
  5089 
  5090 void
  5091 BMessage_delete (void *message)
  5092 {
  5093   delete (BMessage *) message;
  5094 }
  5095 
  5096 static int32
  5097 be_drag_message_thread_entry (void *thread_data)
  5098 {
  5099   BMessenger *messenger;
  5100   BMessage reply;
  5101 
  5102   messenger = (BMessenger *) thread_data;
  5103   messenger->SendMessage (WAIT_FOR_RELEASE, &reply);
  5104 
  5105   return 0;
  5106 }
  5107 
  5108 bool
  5109 be_drag_message (void *view, void *message, bool allow_same_view,
  5110                  void (*block_input_function) (void),
  5111                  void (*unblock_input_function) (void),
  5112                  void (*process_pending_signals_function) (void),
  5113                  bool (*should_quit_function) (void))
  5114 {
  5115   EmacsView *vw = (EmacsView *) view;
  5116   EmacsWindow *window = (EmacsWindow *) vw->Window ();
  5117   BMessage *msg = (BMessage *) message;
  5118   BMessage wait_for_release;
  5119   BMessenger messenger (vw);
  5120   BMessage cancel_message (CANCEL_DROP);
  5121   struct object_wait_info infos[2];
  5122   ssize_t stat;
  5123   thread_id window_thread;
  5124 
  5125   block_input_function ();
  5126 
  5127   if (!allow_same_view)
  5128     window_thread = window->Looper ()->Thread ();
  5129 
  5130   if (!allow_same_view
  5131       && (msg->ReplaceInt64 ("emacs:thread_id", window_thread)
  5132           == B_NAME_NOT_FOUND))
  5133     msg->AddInt64 ("emacs:thread_id", window_thread);
  5134 
  5135   if (!vw->LockLooper ())
  5136     gui_abort ("Failed to lock view looper for drag");
  5137 
  5138   vw->DragMessage (msg, BRect (0, 0, 0, 0));
  5139   vw->UnlockLooper ();
  5140 
  5141   infos[0].object = port_application_to_emacs;
  5142   infos[0].type = B_OBJECT_TYPE_PORT;
  5143   infos[0].events = B_EVENT_READ;
  5144 
  5145   infos[1].object = spawn_thread (be_drag_message_thread_entry,
  5146                                   "Drag waiter thread",
  5147                                   B_DEFAULT_MEDIA_PRIORITY,
  5148                                   (void *) &messenger);
  5149   infos[1].type = B_OBJECT_TYPE_THREAD;
  5150   infos[1].events = B_EVENT_INVALID;
  5151   unblock_input_function ();
  5152 
  5153   if (infos[1].object < B_OK)
  5154     return false;
  5155 
  5156   block_input_function ();
  5157   resume_thread (infos[1].object);
  5158   unblock_input_function ();
  5159 
  5160   drag_and_drop_in_progress = true;
  5161 
  5162   while (true)
  5163     {
  5164       block_input_function ();
  5165       stat = wait_for_objects ((struct object_wait_info *) &infos, 2);
  5166       unblock_input_function ();
  5167 
  5168       if (stat == B_INTERRUPTED || stat == B_TIMED_OUT
  5169           || stat == B_WOULD_BLOCK)
  5170         continue;
  5171 
  5172       if (stat < B_OK)
  5173         gui_abort ("Failed to wait for drag");
  5174 
  5175       if (infos[0].events & B_EVENT_READ)
  5176         process_pending_signals_function ();
  5177 
  5178       if (should_quit_function ())
  5179         {
  5180           /* Do the best we can to prevent something from being
  5181              dropped, since Haiku doesn't provide a way to actually
  5182              cancel drag-and-drop.  */
  5183           if (vw->LockLooper ())
  5184             {
  5185               vw->DragMessage (&cancel_message, BRect (0, 0, 0, 0));
  5186               vw->UnlockLooper ();
  5187             }
  5188 
  5189           messenger.SendMessage (CANCEL_DROP);
  5190           drag_and_drop_in_progress = false;
  5191           return true;
  5192         }
  5193 
  5194       if (infos[1].events & B_EVENT_INVALID)
  5195         {
  5196           drag_and_drop_in_progress = false;
  5197           return false;
  5198         }
  5199 
  5200       infos[0].events = B_EVENT_READ;
  5201       infos[1].events = B_EVENT_INVALID;
  5202     }
  5203 }
  5204 
  5205 bool
  5206 be_drag_and_drop_in_progress (void)
  5207 {
  5208   return drag_and_drop_in_progress;
  5209 }
  5210 
  5211 /* Replay the menu bar click event EVENT.  Return whether or not the
  5212    menu bar actually opened.  */
  5213 bool
  5214 be_replay_menu_bar_event (void *menu_bar,
  5215                           struct haiku_menu_bar_click_event *event)
  5216 {
  5217   BMenuBar *m = (BMenuBar *) menu_bar;
  5218   BMessenger messenger (m);
  5219   BMessage reply, msg (REPLAY_MENU_BAR);
  5220 
  5221   msg.AddPoint ("emacs:point", BPoint (event->x, event->y));
  5222   messenger.SendMessage (&msg, &reply);
  5223   return reply.what == BE_MENU_BAR_OPEN;
  5224 }
  5225 
  5226 void
  5227 BWindow_set_z_group (void *window, enum haiku_z_group z_group)
  5228 {
  5229   EmacsWindow *w = (EmacsWindow *) window;
  5230 
  5231   if (w->LockLooper ())
  5232     {
  5233       if (w->z_group != z_group)
  5234         {
  5235           w->z_group = z_group;
  5236           w->RecomputeFeel ();
  5237 
  5238           if (w->z_group == Z_GROUP_BELOW)
  5239             w->SetFlags (w->Flags () | B_AVOID_FRONT);
  5240           else
  5241             w->SetFlags (w->Flags () & ~B_AVOID_FRONT);
  5242         }
  5243 
  5244       w->UnlockLooper ();
  5245     }
  5246 }
  5247 
  5248 int
  5249 be_get_ui_color (const char *name, uint32_t *color)
  5250 {
  5251   color_which which;
  5252   rgb_color rgb;
  5253 
  5254   which = which_ui_color (name);
  5255 
  5256   if (which == B_NO_COLOR)
  5257     return 1;
  5258 
  5259   rgb = ui_color (which);
  5260   *color = (rgb.blue | rgb.green << 8
  5261             | rgb.red << 16 | 255 << 24);
  5262 
  5263   return 0;
  5264 }
  5265 
  5266 bool
  5267 be_select_font (void (*process_pending_signals_function) (void),
  5268                 bool (*should_quit_function) (void),
  5269                 haiku_font_family_or_style *family,
  5270                 haiku_font_family_or_style *style,
  5271                 int *size, bool allow_monospace_only,
  5272                 int initial_family, int initial_style,
  5273                 int initial_size, bool initial_antialias,
  5274                 bool *disable_antialias)
  5275 {
  5276   EmacsFontSelectionDialog *dialog;
  5277   struct font_selection_dialog_message msg;
  5278   uint32 flags;
  5279   font_family family_buffer;
  5280   font_style style_buffer;
  5281 
  5282   dialog = new EmacsFontSelectionDialog (allow_monospace_only,
  5283                                          initial_family, initial_style,
  5284                                          initial_size, initial_antialias);
  5285   dialog->CenterOnScreen ();
  5286 
  5287   if (dialog->InitCheck () < B_OK)
  5288     {
  5289       dialog->Quit ();
  5290       return false;
  5291     }
  5292 
  5293   dialog->Show ();
  5294   dialog->WaitForChoice (&msg, process_pending_signals_function,
  5295                          should_quit_function);
  5296 
  5297   if (!dialog->LockLooper ())
  5298     gui_abort ("Failed to lock font selection dialog looper");
  5299   dialog->Quit ();
  5300 
  5301   if (msg.cancel)
  5302     return false;
  5303 
  5304   if (get_font_family (msg.family_idx,
  5305                        &family_buffer, &flags) != B_OK
  5306       || get_font_style (family_buffer, msg.style_idx,
  5307                          &style_buffer, &flags) != B_OK)
  5308     return false;
  5309 
  5310   memcpy (family, family_buffer, sizeof *family);
  5311   memcpy (style, style_buffer, sizeof *style);
  5312   *size = msg.size_specified ? msg.size : -1;
  5313   *disable_antialias = msg.disable_antialias;
  5314 
  5315   return true;
  5316 }
  5317 
  5318 void
  5319 BWindow_set_sticky (void *window, bool sticky)
  5320 {
  5321   BWindow *w = (BWindow *) window;
  5322 
  5323   if (w->LockLooper ())
  5324     {
  5325       w->SetFlags (sticky ? (w->Flags ()
  5326                              | B_SAME_POSITION_IN_ALL_WORKSPACES)
  5327                    : w->Flags () & ~B_SAME_POSITION_IN_ALL_WORKSPACES);
  5328 
  5329       w->UnlockLooper ();
  5330     }
  5331 }
  5332 
  5333 status_t
  5334 be_roster_launch (const char *type, const char *file, char **cargs,
  5335                   ptrdiff_t nargs, void *message, team_id *team_id)
  5336 {
  5337   BEntry entry;
  5338   entry_ref ref;
  5339 
  5340   if (type)
  5341     {
  5342       if (message)
  5343         return be_roster->Launch (type, (BMessage *) message,
  5344                                   team_id);
  5345 
  5346       return be_roster->Launch (type, (nargs > INT_MAX
  5347                                        ? INT_MAX : nargs),
  5348                                 cargs, team_id);
  5349     }
  5350 
  5351   if (entry.SetTo (file) != B_OK)
  5352     return B_ERROR;
  5353 
  5354   if (entry.GetRef (&ref) != B_OK)
  5355     return B_ERROR;
  5356 
  5357   if (message)
  5358     return be_roster->Launch (&ref, (BMessage *) message,
  5359                               team_id);
  5360 
  5361   return be_roster->Launch (&ref, (nargs > INT_MAX
  5362                                    ? INT_MAX : nargs),
  5363                             cargs, team_id);
  5364 }
  5365 
  5366 void *
  5367 be_create_pixmap_cursor (void *bitmap, int x, int y)
  5368 {
  5369   BBitmap *bm;
  5370   BCursor *cursor;
  5371 
  5372   bm = (BBitmap *) bitmap;
  5373   cursor = new BCursor (bm, BPoint (x, y));
  5374 
  5375   if (cursor->InitCheck () != B_OK)
  5376     {
  5377       delete cursor;
  5378       return NULL;
  5379     }
  5380 
  5381   return cursor;
  5382 }
  5383 
  5384 void
  5385 be_get_window_decorator_dimensions (void *window, int *left, int *top,
  5386                                     int *right, int *bottom)
  5387 {
  5388   BWindow *wnd;
  5389   BRect frame, window_frame;
  5390 
  5391   wnd = (BWindow *) window;
  5392 
  5393   if (!wnd->LockLooper ())
  5394     gui_abort ("Failed to lock window looper frame");
  5395 
  5396   frame = wnd->DecoratorFrame ();
  5397   window_frame = wnd->Frame ();
  5398 
  5399   if (left)
  5400     *left = window_frame.left - frame.left;
  5401 
  5402   if (top)
  5403     *top = window_frame.top - frame.top;
  5404 
  5405   if (right)
  5406     *right = frame.right - window_frame.right;
  5407 
  5408   if (bottom)
  5409     *bottom = frame.bottom - window_frame.bottom;
  5410 
  5411   wnd->UnlockLooper ();
  5412 }
  5413 
  5414 void
  5415 be_get_window_decorator_frame (void *window, int *left, int *top,
  5416                                int *width, int *height)
  5417 {
  5418   BWindow *wnd;
  5419   BRect frame;
  5420 
  5421   wnd = (BWindow *) window;
  5422 
  5423   if (!wnd->LockLooper ())
  5424     gui_abort ("Failed to lock window looper frame");
  5425 
  5426   frame = wnd->DecoratorFrame ();
  5427 
  5428   *left = frame.left;
  5429   *top = frame.top;
  5430   *width = BE_RECT_WIDTH (frame);
  5431   *height = BE_RECT_HEIGHT (frame);
  5432 
  5433   wnd->UnlockLooper ();
  5434 }
  5435 
  5436 /* Request that a MOVE_EVENT be sent for WINDOW.  This is so that
  5437    frame offsets can be updated after a frame parameter affecting
  5438    decorators changes.  Sending an event instead of updating the
  5439    offsets directly avoids race conditions where events with older
  5440    information are received after the update happens.  */
  5441 void
  5442 be_send_move_frame_event (void *window)
  5443 {
  5444   BWindow *wnd = (BWindow *) window;
  5445   BMessenger msg (wnd);
  5446 
  5447   msg.SendMessage (SEND_MOVE_FRAME_EVENT);
  5448 }
  5449 
  5450 void
  5451 be_lock_window (void *window)
  5452 {
  5453   BWindow *wnd = (BWindow *) window;
  5454 
  5455   if (!wnd->LockLooper ())
  5456     gui_abort ("Failed to lock window looper");
  5457 }
  5458 
  5459 void
  5460 be_unlock_window (void *window)
  5461 {
  5462   BWindow *wnd = (BWindow *) window;
  5463 
  5464   wnd->UnlockLooper ();
  5465 }
  5466 
  5467 void
  5468 be_set_window_fullscreen_mode (void *window, enum haiku_fullscreen_mode mode)
  5469 {
  5470   EmacsWindow *w = (EmacsWindow *) window;
  5471 
  5472   if (!w->LockLooper ())
  5473     gui_abort ("Failed to lock window to set fullscreen mode");
  5474 
  5475   w->SetFullscreen (mode);
  5476   w->UnlockLooper ();
  5477 }
  5478 
  5479 bool
  5480 be_get_explicit_workarea (int *x, int *y, int *width, int *height)
  5481 {
  5482   BDeskbar deskbar;
  5483   BRect zoom;
  5484   deskbar_location location;
  5485 
  5486   location = deskbar.Location ();
  5487 
  5488   if (location != B_DESKBAR_TOP
  5489       && location != B_DESKBAR_BOTTOM)
  5490     return false;
  5491 
  5492   zoom = get_zoom_rect (NULL);
  5493 
  5494   *x = zoom.left;
  5495   *y = zoom.top;
  5496   *width = BE_RECT_WIDTH (zoom);
  5497   *height = BE_RECT_HEIGHT (zoom);
  5498 
  5499   return true;
  5500 }
  5501 
  5502 /* Clear the grab view.  This has to be called manually from some
  5503    places, since we don't get B_MOUSE_UP messages after a popup menu
  5504    is run.  */
  5505 
  5506 void
  5507 be_clear_grab_view (void)
  5508 {
  5509   if (grab_view_locker.Lock ())
  5510     {
  5511       grab_view = NULL;
  5512       grab_view_locker.Unlock ();
  5513     }
  5514 }
  5515 
  5516 void
  5517 be_set_use_frame_synchronization (void *view, bool sync)
  5518 {
  5519   EmacsView *vw;
  5520 
  5521   vw = (EmacsView *) view;
  5522   vw->SetFrameSynchronization (sync);
  5523 }
  5524 
  5525 status_t
  5526 be_write_node_message (const char *path, const char *name, void *message)
  5527 {
  5528   BNode node (path);
  5529   status_t rc;
  5530   ssize_t flat, result;
  5531   char *buffer;
  5532   BMessage *msg;
  5533 
  5534   rc = node.InitCheck ();
  5535   msg = (BMessage *) message;
  5536 
  5537   if (rc < B_OK)
  5538     return rc;
  5539 
  5540   flat = msg->FlattenedSize ();
  5541   if (flat < B_OK)
  5542     return flat;
  5543 
  5544   buffer = new (std::nothrow) char[flat];
  5545   if (!buffer)
  5546     return B_NO_MEMORY;
  5547 
  5548   rc = msg->Flatten (buffer, flat);
  5549   if (rc < B_OK)
  5550     {
  5551       delete[] buffer;
  5552       return rc;
  5553     }
  5554 
  5555   result = node.WriteAttr (name, B_MIME_TYPE, 0,
  5556                            buffer, flat);
  5557   delete[] buffer;
  5558 
  5559   if (result < B_OK)
  5560     return result;
  5561 
  5562   if (result != flat)
  5563     return B_ERROR;
  5564 
  5565   return B_OK;
  5566 }
  5567 
  5568 void
  5569 be_send_message (const char *app_id, void *message)
  5570 {
  5571   BMessenger messenger (app_id);
  5572 
  5573   messenger.SendMessage ((BMessage *) message);
  5574 }

/* [<][>][^][v][top][bottom][index][help] */