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