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