1 /* -*- c-basic-offset:2; tab-width:2; indent-tabs-mode:nil -*- */
2
3 #include <Application.h>
4 #include <Window.h>
5 #include <Rect.h>
6 #include <View.h>
7 #include <Font.h>
8 #include <Bitmap.h>
9 #include <Clipboard.h>
10 #include <Screen.h>
11 #include <Region.h>
12 #include <Beep.h>
13 #include <TranslationUtils.h>
14 #include <Input.h>
15 #include <Alert.h>
16 #include <TextControl.h>
17 #include <LayoutBuilder.h>
18 #include <Button.h>
19 #include <Entry.h>
20 #include <Path.h>
21
22 #include <pthread.h>
23
24 extern "C" {
25 #include "ui_window.h"
26 #include "beos.h"
27 #include "../ui_screen.h"
28 #include "../ui_selection_encoding.h"
29
30 #include <pobl/bl_str.h> /* strdup */
31 #include <pobl/bl_privilege.h>
32 #include <pobl/bl_unistd.h> /* usleep/bl_getuid/bl_getgid */
33 #include <pobl/bl_file.h> /* bl_file_set_cloexec */
34 #include <pobl/bl_debug.h>
35 #include <sys/select.h>
36 #include <mef/ef_utf16_parser.h>
37 }
38
39 #define IS_UISCREEN(win) ((win)->xim_listener)
40
41 class MLWindow : public BWindow {
42 public:
43 MLWindow(BRect frame, const char *title, window_type type, uint32 flags);
44 virtual void WindowActivated(bool active);
45 virtual void FrameResized(float width, float height);
46 virtual void Quit();
47 ui_window_t *uiwindow;
48 };
49
50 class MLView : public BView {
51 private:
52 int32 buttons;
53 int32 dnd_modifiers;
54 const BFont *cur_font;
55
56 public:
57 MLView(BRect frame, const char *name, uint32 resizemode, uint32 flags);
58 virtual void Draw(BRect updaterect);
59 virtual void KeyDown(const char *bytes, int32 numBytes);
60 virtual void MouseDown(BPoint where);
61 virtual void MouseMoved(BPoint where, uint32 code, const BMessage *dragMessage);
62 virtual void MouseUp(BPoint where);
63 virtual void SetFont(const BFont *font, uint32 mask = B_FONT_ALL);
64 virtual void MessageReceived(BMessage *msg);
65 ui_window_t *uiwindow;
66 BMessenger *messenger;
67 };
68
69 class ConnectDialog : public BWindow {
70 private:
71 int button;
72
73 public:
74 ConnectDialog();
75 bool Go();
76 void Position(BWindow *parent);
77 virtual void MessageReceived(BMessage *message);
78 BTextControl *text;
79 };
80
81 enum {
82 MSG_OK = 'ok',
83 MSG_CANCEL = 'can'
84 };
85
86 static pthread_mutex_t mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER;
87
88 /* --- static variables --- */
89
90 static ef_parser_t *utf16_parser;
91
92 /* --- static functions --- */
93
set_input_focus(MLView * view)94 static void set_input_focus(MLView *view) {
95 view->MakeFocus(true);
96
97 XEvent ev;
98
99 ev.type = UI_KEY_FOCUS_IN;
100 ui_window_receive_event(view->uiwindow, &ev);
101 }
102
update_ime_text(ui_window_t * uiwindow,const char * preedit_text)103 static void update_ime_text(ui_window_t *uiwindow, const char *preedit_text) {
104 (*uiwindow->preedit)(uiwindow, preedit_text, NULL);
105 }
106
draw_screen(ui_window_t * uiwindow,BRect update,int force_expose)107 static void draw_screen(ui_window_t *uiwindow, BRect update, int force_expose) {
108 XExposeEvent ev;
109
110 ev.type = UI_EXPOSE;
111 ev.x = update.left;
112 ev.y = update.top;
113 ev.width = update.right - update.left + 1.0;
114 ev.height = update.bottom - update.top + 1.0;
115 ev.force_expose = force_expose;
116
117 ui_window_receive_event(uiwindow, (XEvent *)&ev);
118 uiwindow->update_window_flag = 0;
119 }
120
window_lock(MLWindow * window)121 static void window_lock(MLWindow *window) {
122 #ifdef __DEBUG
123 bl_debug_printf("Locking %p(%s)\n", uiwindow, uiwindow->parent ? "child" : "root");
124 #endif
125
126 #ifdef DEBUG
127 if (!window->IsLocked()) {
128 bl_debug_printf(BL_DEBUG_TAG " Looper is not locked\n");
129 beos_lock();
130 } else
131 #endif
132 {
133 window->UnlockLooper();
134 beos_lock();
135 window->LockLooper();
136 }
137
138 #ifdef __DEBUG
139 bl_debug_printf("Done\n");
140 #endif
141 }
142
view_lock(MLView * view)143 static void view_lock(MLView *view) {
144 #ifdef __DEBUG
145 bl_debug_printf("Locking %p(%s)\n", uiwindow, uiwindow->parent ? "child" : "root");
146 #endif
147
148 #ifdef DEBUG
149 if (!view->Window()->IsLocked()) {
150 bl_debug_printf(BL_DEBUG_TAG " Looper is not locked\n");
151 beos_lock();
152 } else
153 #endif
154 {
155 view->UnlockLooper();
156 beos_lock();
157 view->LockLooper();
158 }
159
160 #ifdef __DEBUG
161 bl_debug_printf("Done\n");
162 #endif
163 }
164
165 /* --- class methods --- */
166
167 /* Lock is unnecessary because no mlterm function is called. */
MLWindow(BRect frame,const char * title,window_type type,uint32 flags)168 MLWindow::MLWindow(BRect frame, const char *title, window_type type, uint32 flags)
169 : BWindow(frame, title, type, flags) {
170 frame.OffsetTo(0, 0);
171 }
172
WindowActivated(bool active)173 void MLWindow::WindowActivated(bool active) {
174 if (!uiwindow) {
175 /* WindowActivated() can be called by BWindow::Quit() in window_dealloc() */
176 return;
177 }
178
179 XEvent ev;
180
181 if (active) {
182 ev.type = UI_FOCUS_IN;
183 } else {
184 ev.type = UI_FOCUS_OUT;
185 }
186
187 window_lock(this);
188
189 ui_window_receive_event(ui_get_root_window(uiwindow), &ev);
190
191 beos_unlock();
192 }
193
194 /*
195 * I don't know why but the value of 'width' or 'height' is 'right - left' or
196 * 'bottom - top'.
197 */
FrameResized(float width,float height)198 void MLWindow::FrameResized(float width, float height) {
199 window_lock(this);
200
201 /* MLWindow::ResizeTo() causes FrameResized() event. */
202 if (uiwindow->width != ((u_int)width) + 1 - uiwindow->hmargin * 2 ||
203 uiwindow->height != ((u_int)height) + 1 - uiwindow->vmargin * 2) {
204 uiwindow->width = width + 1 - uiwindow->hmargin * 2;
205 uiwindow->height = height + 1 - uiwindow->vmargin * 2;
206
207 XEvent ev;
208
209 ev.type = UI_RESIZE;
210 ui_window_receive_event(uiwindow, &ev);
211 }
212
213 beos_unlock();
214 }
215
Quit()216 void MLWindow::Quit() {
217 if (uiwindow) {
218 if (uiwindow->disp->num_roots == 1) {
219 be_app->PostMessage(B_QUIT_REQUESTED);
220 }
221
222 XEvent ev;
223
224 ev.type = UI_CLOSE_WINDOW;
225
226 window_lock(this);
227
228 ui_window_receive_event(uiwindow, &ev);
229
230 /*
231 * Not reach.
232 * window_destroyed() => ui_window_final() => window_dealloc() =>
233 * MLWindow::Quit() => BWindow::Quit()
234 */
235 } else {
236 /* Called from window_dealloc() */
237
238 beos_unlock();
239
240 BWindow::Quit();
241
242 /* Not reach. This thread exits in BWindow::Quit(). */
243 }
244 }
245
246 /* Lock is unnecessary because no mlterm function is called. */
MLView(BRect frame,const char * title,uint32 resizemode,uint32 flags)247 MLView::MLView(BRect frame, const char *title, uint32 resizemode, uint32 flags)
248 : BView(frame, title, resizemode, flags) {
249 SetViewColor(255, 255, 255);
250 SetHighColor(0, 0, 0);
251 SetLowColor(0, 0, 0);
252 SetFontSize(14);
253 SetDrawingMode(B_OP_OVER);
254 cur_font = NULL;
255 buttons = 0;
256 messenger = NULL;
257
258 /* uiwindow is initialized in view_alloc() or window_alloc(). */
259 #if 0
260 uiwindow = NULL;
261 #endif
262 }
263
Draw(BRect update)264 void MLView::Draw(BRect update) {
265 if (!uiwindow || (IS_UISCREEN(uiwindow) && !((ui_screen_t *)uiwindow)->term)) {
266 /* It has been already removed from ui_layout or term has been detached. */
267 return;
268 }
269
270 view_lock(this);
271
272 draw_screen(uiwindow, update, 0);
273
274 beos_unlock();
275 }
276
KeyDown(const char * bytes,int32 numBytes)277 void MLView::KeyDown(const char *bytes, int32 numBytes) {
278 if (!uiwindow || (IS_UISCREEN(uiwindow) && !((ui_screen_t *)uiwindow)->term)) {
279 /* It has been already removed from ui_layout or term has been detached. */
280 return;
281 }
282
283 view_lock(this);
284
285 int32 modifiers;
286
287 Window()->CurrentMessage()->FindInt32((const char*)"modifiers", &modifiers);
288
289 XKeyEvent kev;
290
291 kev.type = UI_KEY_PRESS;
292 kev.state = modifiers & (ShiftMask|ControlMask|Mod1Mask|CommandMask);
293
294 if (numBytes == 1) {
295 if (bytes[0] == B_FUNCTION_KEY) {
296 int32 key;
297
298 Window()->CurrentMessage()->FindInt32((const char*)"key", &key);
299 kev.keysym = (key | 0xf000);
300 kev.utf8 = NULL;
301 } else {
302 kev.keysym = *bytes;
303
304 switch(kev.keysym) {
305 case B_LEFT_ARROW: /* 0x61 (raw key - jp106) */
306 case B_RIGHT_ARROW: /* 0x63 */
307 case B_UP_ARROW: /* 0x57 */
308 case B_DOWN_ARROW: /* 0x62 */
309 case B_INSERT: /* 0x1f */
310 case B_DELETE: /* 0x34 */
311 case B_HOME: /* 0x20 */
312 case B_END: /* 0x35 */
313 case B_PAGE_UP: /* 0x21 */
314 case B_PAGE_DOWN: /* 0x36 */
315 if (kev.state & ControlMask) {
316 int32 key;
317
318 Window()->CurrentMessage()->FindInt32((const char*)"key", &key); /* raw key */
319 if (key <= 0x1e || (0x22 <= key && key <= 0x33) || (0x37 <= key && key <= 0x56) ||
320 (0x58 <= key && key <= 0x60) || 0x64 <= key) {
321 kev.utf8 = bytes;
322 break;
323 }
324 }
325
326 kev.keysym |= 0xe000;
327 kev.utf8 = NULL;
328 break;
329
330 case B_KATAKANA_HIRAGANA:
331 case B_HANKAKU_ZENKAKU:
332 case B_HANGUL:
333 case B_HANGUL_HANJA:
334 kev.utf8 = NULL;
335 break;
336
337 default:
338 kev.utf8 = bytes;
339 break;
340 }
341 }
342 } else {
343 kev.keysym = 0;
344 kev.utf8 = bytes;
345 }
346
347 ui_window_receive_event(uiwindow, (XEvent *)&kev);
348
349 beos_unlock();
350 }
351
MouseDown(BPoint where)352 void MLView::MouseDown(BPoint where) {
353 if (!uiwindow || (IS_UISCREEN(uiwindow) && !((ui_screen_t *)uiwindow)->term)) {
354 /* It has been already removed from ui_layout or term has been detached. */
355 return;
356 }
357
358 view_lock(this);
359
360 if (!IsFocus()) {
361 set_input_focus(this);
362 }
363
364 int32 clicks;
365 int64 when; /* microsec */
366 int32 modifiers;
367
368 Window()->CurrentMessage()->FindInt32((const char*)"buttons", &this->buttons);
369 Window()->CurrentMessage()->FindInt32((const char*)"clicks", &clicks);
370 Window()->CurrentMessage()->FindInt64((const char*)"when", &when);
371 Window()->CurrentMessage()->FindInt32((const char*)"modifiers", &modifiers);
372
373 XButtonEvent bev;
374
375 bev.type = UI_BUTTON_PRESS;
376 bev.time = when / 1000; /* msec */
377 bev.x = where.x;
378 bev.y = where.y;
379 bev.state = modifiers & (ShiftMask|ControlMask|Mod1Mask|CommandMask);
380 bev.click_count = clicks;
381 if (buttons == 0) {
382 bev.button = 0;
383 } else {
384 if (buttons & B_PRIMARY_MOUSE_BUTTON) {
385 bev.button = 1;
386 } else if (buttons & B_SECONDARY_MOUSE_BUTTON) {
387 bev.button = 3;
388 } else /* if (buttons & B_TERTIARY_MOUSE_BUTTON) */ {
389 bev.button = 2;
390 }
391 }
392
393 ui_window_receive_event(uiwindow, (XEvent *)&bev);
394
395 beos_unlock();
396 }
397
MouseMoved(BPoint where,uint32 code,const BMessage * dragMessage)398 void MLView::MouseMoved(BPoint where, uint32 code, const BMessage *dragMessage) {
399 if (dragMessage) {
400 Window()->CurrentMessage()->FindInt32((const char*)"modifiers", &dnd_modifiers);
401
402 return;
403 }
404
405 if (!uiwindow || (IS_UISCREEN(uiwindow) && !((ui_screen_t *)uiwindow)->term)) {
406 /* It has been already removed from ui_layout or term has been detached. */
407 return;
408 }
409
410 view_lock(this);
411
412 int32 buttons;
413 int64 when; /* microsec */
414 int32 modifiers;
415
416 Window()->CurrentMessage()->FindInt32((const char*)"buttons", &buttons);
417 Window()->CurrentMessage()->FindInt64((const char*)"when", &when);
418 Window()->CurrentMessage()->FindInt32((const char*)"modifiers", &modifiers);
419
420 XMotionEvent mev;
421
422 mev.time = when / 1000; /* msec */
423 mev.x = where.x;
424 mev.y = where.y;
425 mev.state = modifiers & (ShiftMask|ControlMask|Mod1Mask|CommandMask);
426 if (buttons == 0) {
427 mev.type = UI_POINTER_MOTION;
428 } else {
429 if (buttons & B_PRIMARY_MOUSE_BUTTON) {
430 mev.state |= Button1Mask;
431 }
432 if (buttons & B_SECONDARY_MOUSE_BUTTON) {
433 mev.state |= Button3Mask;
434 }
435 if (buttons & B_TERTIARY_MOUSE_BUTTON) {
436 mev.state |= Button2Mask;
437 }
438 mev.type = UI_BUTTON_MOTION;
439 }
440
441 ui_window_receive_event(uiwindow, (XEvent *)&mev);
442
443 beos_unlock();
444 }
445
MouseUp(BPoint where)446 void MLView::MouseUp(BPoint where) {
447 if (!uiwindow || (IS_UISCREEN(uiwindow) && !((ui_screen_t *)uiwindow)->term)) {
448 /* It has been already removed from ui_layout or term has been detached. */
449 return;
450 }
451
452 view_lock(this);
453
454 int32 clicks;
455 int64 when; /* microsec */
456
457 Window()->CurrentMessage()->FindInt32((const char*)"clicks", &clicks);
458 Window()->CurrentMessage()->FindInt64((const char*)"when", &when);
459
460 XButtonEvent bev;
461
462 bev.type = UI_BUTTON_RELEASE;
463 bev.time = when / 1000; /* msec */
464 bev.x = where.x;
465 bev.y = where.y;
466 bev.state = 0;
467 if (buttons == 0) {
468 bev.button = 0;
469 } else {
470 if (buttons & B_PRIMARY_MOUSE_BUTTON) {
471 bev.button = 1;
472 } else if (buttons & B_SECONDARY_MOUSE_BUTTON) {
473 bev.button = 3;
474 } else /* if (buttons & B_TERTIARY_MOUSE_BUTTON) */ {
475 bev.button = 2;
476 }
477 }
478 this->buttons = 0;
479
480 ui_window_receive_event(uiwindow, (XEvent *)&bev);
481
482 beos_unlock();
483 }
484
485 /*
486 * SetFont() doesn't check if the specified font is different from the current font,
487 * while SetHighColor() checks if the specified RGB is different from the current RGB.
488 * (https://github.com/haiku/haiku/blob/master/src/kits/interface/View.cpp)
489 */
SetFont(const BFont * font,uint32 mask)490 void MLView::SetFont(const BFont *font, uint32 mask) {
491 if (cur_font != font) {
492 cur_font = font;
493 BView::SetFont(font, mask);
494 }
495 }
496
MessageReceived(BMessage * message)497 void MLView::MessageReceived(BMessage *message) {
498 if (message->what == B_SIMPLE_DATA) {
499 int32 count = 0;
500
501 #if 0
502 status_t s;
503 int32 action;
504
505 while ((s = message->FindInt32("be:actions", count++, &action)) == B_OK) {
506 bl_debug_printf(BL_DEBUG_TAG "ACTION: %x (COYP %x MOVE %x)\n",
507 action, B_COPY_TARGET, B_MOVE_TARGET);
508 }
509 #ifdef DEBUG
510 if (s == B_NAME_NOT_FOUND) {
511 bl_debug_printf(BL_DEBUG_TAG " be:actions is not found.\n");
512 }
513 #endif
514
515 count = 0;
516 #endif
517
518 entry_ref ref;
519 while (message->FindRef("refs", count++, &ref) == B_OK) {
520 BPath path(&ref);
521
522 view_lock(this);
523
524 if (dnd_modifiers & ShiftMask) {
525 (*uiwindow->set_xdnd_config)(uiwindow, NULL, "scp", (char*)path.Path());
526 } else {
527 XSelectionNotifyEvent ev;
528 ev.type = UI_SELECTION_NOTIFIED;
529 ev.data = (char*)path.Path();
530 ev.len = strlen(ev.data);
531
532 ui_window_receive_event(uiwindow, (XEvent*)&ev);
533 }
534
535 beos_unlock();
536 }
537 } else if (message->what == B_INPUT_METHOD_EVENT) {
538 if (IS_UISCREEN(uiwindow) && !((ui_screen_t *)uiwindow)->term) {
539 /* It has been already removed from ui_layout or term has been detached. */
540 return;
541 }
542
543 view_lock(this);
544
545 int32 opcode;
546
547 /*
548 * If a focused view is changed from a view where you are inputting with
549 * ime to another in splitted screen, following check enclosed by
550 * #if 1 ... #endif is necessary.
551 */
552 if (message->FindInt32("be:opcode", &opcode) == B_OK) {
553 if (opcode == B_INPUT_METHOD_STARTED) {
554 BMessenger m;
555
556 if (message->FindMessenger("be:reply_to", &m) == B_OK) {
557 if (messenger) {
558 delete messenger;
559 }
560
561 messenger = new BMessenger(m);
562 }
563 } else if (opcode == B_INPUT_METHOD_STOPPED) {
564 if (messenger) {
565 delete messenger;
566 messenger = NULL;
567 }
568 } else if (opcode == B_INPUT_METHOD_CHANGED) {
569 const char *str;
570
571 if (message->FindString("be:string", &str) != B_OK || *str == '\0') {
572 update_ime_text(uiwindow, "");
573
574 goto end;
575 }
576
577 bool confirmed;
578
579 if (message->FindBool("be:confirmed", &confirmed) == B_OK && confirmed) {
580 update_ime_text(uiwindow, "");
581
582 XKeyEvent kev;
583
584 kev.type = UI_KEY_PRESS;
585 kev.state = 0;
586 kev.keysym = 0;
587 kev.utf8 = str;
588
589 ui_window_receive_event(uiwindow, (XEvent *)&kev);
590 } else {
591 int32 start;
592 int32 end;
593 #if 0
594 int32 count = 0;
595
596 while (message->FindInt32("be:clause_start", count, &start) == B_OK &&
597 message->FindInt32("be:clause_end", count, &end) == B_OK) {
598 bl_debug_printf("Clause %d: %d-%d\n", count, start, end);
599 count++;
600 }
601 #endif
602
603 message->FindInt32("be:selection", 1, &end);
604 if (end > 0) {
605 message->FindInt32("be:selection", 0, &start);
606
607 char str2[strlen(str) + 10];
608 char *p = str2;
609
610 memcpy(p, str, start);
611 strcpy((p += start), "\x1b[7m");
612
613 int32 len = end - start;
614 strncpy((p += 4), str + start, len);
615 strcpy((p += len), "\x1b[27m");
616 strcpy((p += 5), str + end);
617
618 update_ime_text(uiwindow, str2);
619 } else {
620 update_ime_text(uiwindow, str);
621 }
622 }
623 } else if (opcode == B_INPUT_METHOD_LOCATION_REQUEST && messenger) {
624 int x;
625 int y;
626
627 if (!uiwindow->xim_listener ||
628 !(*uiwindow->xim_listener->get_spot)(uiwindow->xim_listener->self, &x, &y)) {
629 x = y = 0;
630 }
631
632 BMessage message(B_INPUT_METHOD_EVENT);
633 message.AddInt32("be:opcode", B_INPUT_METHOD_LOCATION_REQUEST);
634 BPoint where((float)x, (float)y);
635 ConvertToScreen(&where);
636
637 float height = ui_line_height((ui_screen_t*)uiwindow);
638 message.AddPoint("be:location_reply", where);
639 message.AddFloat("be:height_reply", height);
640 messenger->SendMessage(&message);
641 }
642 }
643
644 end:
645 beos_unlock();
646 } else if (message->what == B_MOUSE_WHEEL_CHANGED) {
647 int64 when; /* microsec */
648 float y;
649 XButtonEvent bev;
650
651 message->FindFloat("be:wheel_delta_y", &y);
652 message->FindInt64("be:when", &when);
653
654 bev.type = UI_BUTTON_PRESS;
655 bev.time = when / 1000; /* msec */
656 bev.x = 0;
657 bev.y = 0;
658 bev.state = 0;
659 bev.click_count = 1;
660 if (y < 0) {
661 bev.button = 4;
662 } else {
663 bev.button = 5;
664 }
665
666 view_lock(this);
667 ui_window_receive_event(uiwindow, (XEvent *)&bev);
668 beos_unlock();
669 } else {
670 BView::MessageReceived(message);
671 }
672 }
673
674 /* --- global functions --- */
675
view_alloc(ui_window_t * uiwindow,int x,int y,u_int width,u_int height)676 void view_alloc(ui_window_t *uiwindow, int x, int y, u_int width, u_int height) {
677 uint32 flags = B_WILL_DRAW;
678
679 if (uiwindow->key_pressed) {
680 flags |= B_INPUT_METHOD_AWARE;
681 }
682
683 MLView *view = new MLView(BRect(x, y, x + width - 1, y + height - 1), "mlterm",
684 B_FOLLOW_NONE, flags);
685
686 MLWindow *win = (MLWindow*)uiwindow->parent->my_window;
687 if (win->LockLooperWithTimeout(B_INFINITE_TIMEOUT) != B_OK) {
688 delete view;
689
690 return;
691 }
692
693 view->uiwindow = uiwindow;
694 win->AddChild(view);
695 uiwindow->my_window = (void*)view;
696
697 if (uiwindow->inputtable) {
698 view->MakeFocus(true);
699 }
700
701 win->UnlockLooper();
702 }
703
view_dealloc(void * view)704 void view_dealloc(/* BView */ void *view) {
705 BWindow *win = ((BView*)view)->Window();
706
707 if (win->LockLooperWithTimeout(B_INFINITE_TIMEOUT) != B_OK) {
708 return;
709 }
710
711 win->RemoveChild((BView*)view);
712 ((MLView*)view)->uiwindow = None;
713 delete (BView*)view;
714
715 win->UnlockLooper();
716 }
717
view_update(void * view,int force_expose)718 void view_update(/* BView */ void *view, int force_expose) {
719 ui_window_t *uiwindow = ((MLView*)view)->uiwindow;
720 int x;
721 int y;
722
723 if (!uiwindow->xim_listener ||
724 !(*uiwindow->xim_listener->get_spot)(uiwindow->xim_listener->self, &x, &y)) {
725 x = y = 0;
726 }
727
728 x += (uiwindow->hmargin);
729 y += (uiwindow->vmargin);
730
731 draw_screen(uiwindow, BRect(x, y, x, y), force_expose);
732 }
733
view_set_clip(void * view,int x,int y,u_int width,u_int height)734 void view_set_clip(/* BView */ void *view, int x, int y, u_int width, u_int height) {
735 if (((BView*)view)->LockLooperWithTimeout(B_INFINITE_TIMEOUT) != B_OK) {
736 return;
737 }
738
739 BRegion *region = new BRegion(BRect(x, y, x + width - 1, y + height - 1));
740 ((BView*)view)->ConstrainClippingRegion(region);
741
742 ((BView*)view)->UnlockLooper();
743 }
744
view_unset_clip(void * view)745 void view_unset_clip(/* BView */ void *view) {
746 if (((BView*)view)->LockLooperWithTimeout(B_INFINITE_TIMEOUT) != B_OK) {
747 return;
748 }
749
750 ((BView*)view)->ConstrainClippingRegion(NULL);
751
752 ((BView*)view)->UnlockLooper();
753 }
754
view_draw_string(void * view,ui_font_t * font,ui_color_t * fg_color,int x,int y,char * str,size_t len)755 void view_draw_string(/* BView */ void *view, ui_font_t *font, ui_color_t *fg_color,
756 int x, int y, char *str, size_t len) {
757 if (((BView*)view)->LockLooperWithTimeout(B_INFINITE_TIMEOUT) != B_OK) {
758 return;
759 }
760
761 u_int32_t pixel = fg_color->pixel;
762 ((BView*)view)->SetHighColor((pixel >> 16) & 0xff, (pixel >> 8) & 0xff, pixel & 0xff,
763 (pixel >> 24) & 0xff);
764 ((BView*)view)->SetFont((BFont*)font->xfont->fid);
765
766 x += font->x_off;
767
768 /*
769 * https://www.haiku-os.org/legacy-docs/bebook/BView.html
770 * The BeOS draws text one pixel above the logical baseline to maintain
771 * compatibility with an earlier version of one of our most commonly-used font
772 * rasterizers. This affects both fonts and BShapes representing glyphs
773 * (see BFont::GetGlyphShapes(). To draw text at the right place, add one to
774 * the Y coordinate when calling MovePenTo() or specifying a BPoint at which
775 * to begin drawing.
776 */
777 ((BView*)view)->MovePenTo(x, y + 1);
778 ((BView*)view)->DrawString(str, len);
779
780 if (font->double_draw_gap) {
781 ((BView*)view)->MovePenTo(x + font->double_draw_gap, y + 1);
782 ((BView*)view)->DrawString(str, len);
783 }
784
785 ((BView*)view)->UnlockLooper();
786 }
787
view_draw_string16(void * view,ui_font_t * font,ui_color_t * fg_color,int x,int y,XChar2b * str,size_t len)788 void view_draw_string16(/* BView */ void *view, ui_font_t *font, ui_color_t *fg_color,
789 int x, int y, XChar2b *str, size_t len) {
790 if (!utf16_parser) {
791 utf16_parser = ef_utf16le_parser_new(); /* XXX leaked */
792 }
793 ef_conv_t *utf8_conv = ui_get_selection_conv(1);
794
795 char str2[len * UTF_MAX_SIZE];
796
797 (*utf16_parser->init)(utf16_parser);
798 (*utf16_parser->set_str)(utf16_parser, (u_char*)str, len * 2);
799 (*utf8_conv->init)(utf8_conv);
800 len = (*utf8_conv->convert)(utf8_conv, (u_char*)str2, len * UTF_MAX_SIZE, utf16_parser);
801
802 /* LockLooper() is called in view_draw_string() */
803 view_draw_string(view, font, fg_color, x, y, str2, len);
804 }
805
view_fill_with(void * view,ui_color_t * color,int x,int y,u_int width,u_int height)806 void view_fill_with(/* BView */ void *view, ui_color_t *color, int x, int y,
807 u_int width /* > 0 */, u_int height /* > 0 */) {
808 if (((BView*)view)->LockLooperWithTimeout(B_INFINITE_TIMEOUT) != B_OK) {
809 return;
810 }
811
812 u_long pixel = color->pixel;
813 ((BView*)view)->SetLowColor((pixel >> 16) & 0xff, (pixel >> 8) & 0xff, pixel & 0xff,
814 (pixel >> 24) & 0xff);
815 ((BView*)view)->FillRect(BRect(x, y, x + width - 1, y + height - 1), B_SOLID_LOW);
816
817 ((BView*)view)->UnlockLooper();
818 }
819
view_draw_rect_frame(void * view,ui_color_t * color,int x1,int y1,int x2,int y2)820 void view_draw_rect_frame(/* BView */ void *view, ui_color_t *color, int x1, int y1,
821 int x2, int y2) {
822 u_long pixel = color->pixel;
823 rgb_color rgb;
824
825 rgb.red = (pixel >> 16) & 0xff;
826 rgb.green = (pixel >> 8) & 0xff;
827 rgb.blue = pixel & 0xff;
828 rgb.alpha = (pixel >> 24) & 0xff;
829
830 if (((BView*)view)->LockLooperWithTimeout(B_INFINITE_TIMEOUT) != B_OK) {
831 return;
832 }
833
834 ((BView*)view)->BeginLineArray(4);
835 ((BView*)view)->AddLine(BPoint(x1, y1), BPoint(x1, y2), rgb);
836 ((BView*)view)->AddLine(BPoint(x1, y2), BPoint(x2, y2), rgb);
837 ((BView*)view)->AddLine(BPoint(x2, y1), BPoint(x2, y2), rgb);
838 ((BView*)view)->AddLine(BPoint(x1, y1), BPoint(x2, y1), rgb);
839 ((BView*)view)->EndLineArray();
840
841 ((BView*)view)->UnlockLooper();
842 }
843
view_copy_area(void * view,Pixmap src,int src_x,int src_y,u_int width,u_int height,int dst_x,int dst_y)844 void view_copy_area(/* BView */ void *view, Pixmap src, int src_x, int src_y,
845 u_int width, u_int height, int dst_x, int dst_y) {
846 if (((BView*)view)->LockLooperWithTimeout(B_INFINITE_TIMEOUT) != B_OK) {
847 return;
848 }
849
850 ((BView*)view)->DrawBitmap((BBitmap*)src,
851 BRect(src_x, src_y, src_x + width - 1, src_y + height - 1),
852 BRect(dst_x, dst_y, dst_x + width - 1, dst_y + height - 1));
853
854 ((BView*)view)->UnlockLooper();
855 }
856
view_scroll(void * view,int src_x,int src_y,u_int width,u_int height,int dst_x,int dst_y)857 void view_scroll(/* BView */ void *view, int src_x, int src_y, u_int width,
858 u_int height, int dst_x, int dst_y) {
859 #if 0
860 if (((BView*)view)->LockLooperWithTimeout(B_INFINITE_TIMEOUT) != B_OK) {
861 return;
862 }
863
864 ((BView*)view)->CopyBits(BRect(src_x, src_y, src_x + width - 1, src_y + height - 1),
865 BRect(dst_x, dst_y, dst_x + width - 1, dst_y + height - 1));
866
867 ((BView*)view)->UnlockLooper();
868 #endif
869 }
870
view_bg_color_changed(void * view)871 void view_bg_color_changed(/* BView */ void *view) {
872 }
873
view_visual_bell(void * view)874 void view_visual_bell(/* BView */ void *view) {
875 if (((BView*)view)->LockLooperWithTimeout(B_INFINITE_TIMEOUT) != B_OK) {
876 return;
877 }
878
879 u_long pixel = ((MLView*)view)->uiwindow->fg_color.pixel;
880 ((BView*)view)->SetLowColor((pixel >> 16) & 0xff, (pixel >> 8) & 0xff, pixel & 0xff,
881 (pixel >> 24) & 0xff);
882
883 ui_window_t *win = ((MLView*)view)->uiwindow;
884 ((BView*)view)->FillRect(BRect(0, 0, ACTUAL_WIDTH(win) - 1, ACTUAL_HEIGHT(win) - 1), B_SOLID_LOW);
885
886 ((BView*)view)->UnlockLooper();
887
888 usleep(100000); /* 100 msec */
889
890 draw_screen(((MLView*)view)->uiwindow,
891 BRect(0, 0, ACTUAL_WIDTH(win) - 1, ACTUAL_HEIGHT(win) - 1), 1);
892 }
893
view_set_input_focus(void * view)894 void view_set_input_focus(/* BView */ void *view) {
895 if (((BView*)view)->LockLooperWithTimeout(B_INFINITE_TIMEOUT) != B_OK) {
896 return;
897 }
898
899 set_input_focus((MLView*)view);
900
901 ((BView*)view)->UnlockLooper();
902 }
903
view_resize(void * view,u_int width,u_int height)904 void view_resize(/* BView */ void *view, u_int width, u_int height) {
905 if (((BView*)view)->LockLooperWithTimeout(B_INFINITE_TIMEOUT) != B_OK) {
906 return;
907 }
908
909 ((BView*)view)->ResizeTo((float)width - 1.0, (float)height - 1.0);
910
911 ((BView*)view)->UnlockLooper();
912 }
913
view_move(void * view,int x,int y)914 void view_move(/* BView */ void *view, int x, int y) {
915 if (((BView*)view)->LockLooperWithTimeout(B_INFINITE_TIMEOUT) != B_OK) {
916 return;
917 }
918
919 ((BView*)view)->MoveTo((float)x, (float)y);
920
921 ((BView*)view)->UnlockLooper();
922 }
923
view_set_hidden(void * view,int flag)924 void view_set_hidden(/* BView */ void *view, int flag) {
925 }
926
view_reset_uiwindow(ui_window_t * uiwindow)927 void view_reset_uiwindow(ui_window_t *uiwindow) {
928 ((MLView*)uiwindow->my_window)->uiwindow = uiwindow;
929 }
930
window_alloc(ui_window_t * root,int x,int y,u_int width,u_int height,int popup,int geom_hint)931 void window_alloc(ui_window_t *root, int x, int y, u_int width, u_int height, int popup,
932 int geom_hint) {
933 MLWindow *window;
934
935 if (popup) {
936 window = new MLWindow(BRect(x, y, x + width - 1, y + height - 1), "",
937 B_BORDERED_WINDOW,
938 B_NOT_RESIZABLE|B_NOT_CLOSABLE|B_NOT_ZOOMABLE|B_NOT_MINIMIZABLE|
939 B_NOT_MOVABLE|B_AVOID_FOCUS|B_NOT_ANCHORED_ON_ACTIVATE);
940
941 MLView *view = new MLView(BRect(0, 0, width - 1, height - 1), "IM", B_FOLLOW_NONE, B_WILL_DRAW);
942
943 view->uiwindow = root;
944 window->AddChild(view);
945 } else {
946 /* XXX */
947 static int x_count = 0;
948 static int y_count = 0;
949 BRect r = BScreen().Frame();
950
951 if ((geom_hint & XValue) == 0) {
952 x = ((r.right - width) / 8) * x_count + 50;
953 if (++x_count == 8) {
954 x_count = 0;
955 }
956 }
957 if ((geom_hint & YValue) == 0) {
958 y = ((r.bottom - height) / 8) * y_count + 50;
959 if (++y_count == 8) {
960 y_count = 0;
961 }
962 }
963
964 window = new MLWindow(BRect(x, y, x + width - 1, y + height - 1),
965 "mlterm", B_DOCUMENT_WINDOW, 0);
966 if (root->disp->width == 0) {
967 BScreen *screen = new BScreen(window);
968 BRect rect = screen->Frame();
969 root->disp->width = rect.right + 1;
970 root->disp->height = rect.bottom + 1;
971 delete screen;
972 }
973 }
974
975 window->uiwindow = root;
976 root->my_window = (void*)window;
977 }
978
window_show(void * window)979 void window_show(void *window) {
980 if (((BWindow*)window)->LockLooperWithTimeout(B_INFINITE_TIMEOUT) != B_OK) {
981 return;
982 }
983
984 ((BWindow*)window)->Show();
985
986 ((BWindow*)window)->UnlockLooper();
987 }
988
window_dealloc(void * window)989 void window_dealloc(/* BWindow */ void *window) {
990 if (((BWindow*)window)->LockLooperWithTimeout(B_INFINITE_TIMEOUT) != B_OK) {
991 return;
992 }
993
994 ((MLWindow*)window)->uiwindow = None;
995
996 ((BWindow*)window)->Quit();
997 /* Not reach. This thread exits in BWindow::Quit(). */
998 }
999
window_move(void * window,int x,int y)1000 void window_move(/* BWindow */ void *window, int x, int y) {
1001 if (((BWindow*)window)->LockLooperWithTimeout(B_INFINITE_TIMEOUT) != B_OK) {
1002 return;
1003 }
1004
1005 ((BWindow*)window)->MoveTo((float)x, (float)y);
1006
1007 ((BWindow*)window)->UnlockLooper();
1008 }
1009
window_resize(void * window,int width,int height)1010 void window_resize(/* BWindow */ void *window, int width, int height) {
1011 if (((BWindow*)window)->LockLooperWithTimeout(B_INFINITE_TIMEOUT) != B_OK) {
1012 return;
1013 }
1014
1015 ((BWindow*)window)->ResizeTo((float)width - 1.0, (float)height - 1.0);
1016
1017 BView *view;
1018 if ((view = (BView*)window_get_orphan(window, 0))) {
1019 ((BView*)view)->ResizeTo((float)width - 1.0, (float)height - 1.0);
1020 }
1021
1022 ((BWindow*)window)->UnlockLooper();
1023 }
1024
window_get_position(void * window,int * x,int * y)1025 void window_get_position(/* BWindow */ void *window, int *x, int *y) {
1026 BRect rect = ((BWindow*)window)->Frame();
1027 *x = rect.left;
1028 *y = rect.top;
1029 }
1030
window_set_title(void * window,const char * title)1031 void window_set_title(/* BWindow */ void *window, const char *title /* utf8 */) {
1032 if (((BWindow*)window)->LockLooperWithTimeout(B_INFINITE_TIMEOUT) != B_OK) {
1033 return;
1034 }
1035
1036 ((BWindow*)window)->SetTitle(title);
1037
1038 ((BWindow*)window)->UnlockLooper();
1039 }
1040
window_get_orphan(void * window,int idx)1041 void *window_get_orphan(void *window, int idx) {
1042 if (((MLWindow*)window)->uiwindow->num_children == 0) {
1043 void *child = ((BWindow*)window)->ChildAt(idx);
1044
1045 return child;
1046 } else {
1047 return NULL;
1048 }
1049 }
1050
app_urgent_bell(int on)1051 void app_urgent_bell(int on) {
1052 }
1053
beos_create_font(const char * font_family,float size,int is_italic,int is_bold)1054 void *beos_create_font(const char *font_family, float size, int is_italic, int is_bold) {
1055 BFont *bfont = new BFont();
1056
1057 bfont->SetFamilyAndStyle(font_family, is_bold ? "Bold" : "Regular");
1058 bfont->SetSpacing(B_FIXED_SPACING);
1059 bfont->SetSize(size);
1060 if (is_italic) {
1061 bfont->SetShear(100.0);
1062 }
1063
1064 return bfont;
1065 }
1066
1067 #ifdef USE_OT_LAYOUT
beos_get_font_family(void * bfont)1068 char *beos_get_font_family(void *bfont) {
1069 font_family family;
1070
1071 ((BFont*)bfont)->GetFamilyAndStyle(&family, NULL);
1072
1073 return strdup(family);
1074 }
1075 #endif
1076
beos_release_font(void * bfont)1077 void beos_release_font(void *bfont) {
1078 delete (BFont*)bfont;
1079 }
1080
beos_font_get_metrics(void * bfont,u_int * width,u_int * height,u_int * ascent)1081 void beos_font_get_metrics(void *bfont, u_int *width, u_int *height, u_int *ascent) {
1082 const char *strs[] = { "M" };
1083 int32 lens[] = { 1 };
1084 float widths[1];
1085
1086 ((BFont*)bfont)->GetStringWidths(strs, lens, 1, widths);
1087 *width = widths[0] + 0.5;
1088
1089 font_height height_info;
1090 ((BFont*)bfont)->GetHeight(&height_info);
1091 *height = (height_info.ascent + height_info.descent + height_info.leading) + 0.5;
1092 *ascent = (height_info.ascent + 0.5);
1093 }
1094
beos_font_get_advance(void * bfont,int size_attr,unichar * utf16,u_int len,u_int32_t glyph)1095 u_int beos_font_get_advance(void *bfont, int size_attr,
1096 unichar *utf16, u_int len, u_int32_t glyph) {
1097 if (!utf16_parser) {
1098 /* XXX leaked */
1099 utf16_parser = ef_utf16le_parser_new();
1100 }
1101 ef_conv_t *utf8_conv = ui_get_selection_conv(1);
1102
1103 char utf8[len * UTF_MAX_SIZE];
1104
1105 (*utf16_parser->init)(utf16_parser);
1106 (*utf16_parser->set_str)(utf16_parser, (u_char*)utf16, len * 2);
1107 (*utf8_conv->init)(utf8_conv);
1108 len = (*utf8_conv->convert)(utf8_conv, (u_char*)utf8, len * UTF_MAX_SIZE, utf16_parser);
1109
1110 const char *strs[] = { utf8 };
1111 int32 lens[] = { len };
1112 float widths[1];
1113
1114 ((BFont*)bfont)->GetStringWidths(strs, lens, 1, widths);
1115
1116 return (u_int)(widths[0] + 0.5);
1117 }
1118
beos_clipboard_set(const u_char * utf8,size_t len)1119 void beos_clipboard_set(const u_char *utf8, size_t len) {
1120 if (be_clipboard->Lock()) {
1121 be_clipboard->Clear();
1122
1123 BMessage *clip = be_clipboard->Data();
1124 clip->AddData("text/plain", B_MIME_TYPE, utf8, len);
1125 be_clipboard->Commit();
1126 be_clipboard->Unlock();
1127 }
1128 }
1129
beos_clipboard_get(u_char ** str,size_t * len)1130 int beos_clipboard_get(u_char **str, size_t *len) {
1131 if (be_clipboard->Lock()) {
1132 BMessage *clip = be_clipboard->Data();
1133
1134 clip->FindData("text/plain", B_MIME_TYPE, (const void **)str, (ssize_t*)len);
1135 be_clipboard->Unlock();
1136
1137 return 1;
1138 } else {
1139 return 0;
1140 }
1141 }
1142
beos_beep(void)1143 void beos_beep(void) {
1144 beep();
1145 }
1146
beos_create_image(const void * data,u_int len,u_int width,u_int height)1147 void *beos_create_image(const void *data, u_int len, u_int width, u_int height) {
1148 BBitmap *bitmap;
1149
1150 if ((bitmap = new BBitmap(BRect(0, 0, width - 1, height - 1), 0, B_RGBA32))) {
1151 bitmap->SetBits(data, len, 0, B_RGBA32);
1152 }
1153
1154 return bitmap;
1155 }
1156
beos_destroy_image(void * bitmap)1157 void beos_destroy_image(void *bitmap) {
1158 delete (BBitmap*)bitmap;
1159 }
1160
beos_load_image(const char * path,u_int * width,u_int * height)1161 void *beos_load_image(const char *path, u_int *width, u_int *height) {
1162 BBitmap *bitmap;
1163
1164 if ((bitmap = BTranslationUtils::GetBitmap(path))) {
1165 BRect rect = bitmap->Bounds();
1166 *width = rect.right + 1;
1167 *height = rect.bottom + 1;
1168 }
1169
1170 return bitmap;
1171 }
1172
beos_resize_image(void * bitmap,u_int width,u_int height)1173 void *beos_resize_image(void *bitmap, u_int width, u_int height) {
1174 BRect rect(0, 0, width - 1, height - 1);
1175 BBitmap *new_bitmap = new BBitmap(rect, B_RGBA32, true);
1176 BView *view = new BView(rect, "", B_FOLLOW_ALL_SIDES, 0);
1177 new_bitmap->AddChild(view);
1178 new_bitmap->Lock();
1179 view->DrawBitmap((BBitmap*)bitmap, ((BBitmap*)bitmap)->Bounds(), rect);
1180 new_bitmap->Unlock();
1181
1182 new_bitmap->RemoveChild(view);
1183 delete view;
1184
1185 delete (BBitmap*)bitmap;
1186
1187 return new_bitmap;
1188 }
1189
beos_get_bits(void * bitmap)1190 u_char *beos_get_bits(void *bitmap) {
1191 return (u_char*)((BBitmap*)bitmap)->Bits();
1192 }
1193
ConnectDialog()1194 ConnectDialog::ConnectDialog()
1195 : BWindow(BRect(0, 0, 200, 100), "Password", B_MODAL_WINDOW,
1196 B_NOT_RESIZABLE|B_NOT_CLOSABLE|B_NOT_ZOOMABLE|B_NOT_MINIMIZABLE|B_NOT_MOVABLE, 0) {
1197 BButton *ok = new BButton(BRect(0, 0, 100, 100), "OkButton", "OK", new BMessage(MSG_OK));
1198 BButton *cancel = new BButton(BRect(0, 0, 100, 100), "CancelButton", "Cancel",
1199 new BMessage(MSG_CANCEL));
1200
1201 text = new BTextControl("", "Password", "", NULL);
1202 text->TextView()->HideTyping(true);
1203
1204 BLayoutBuilder::Group<>(this, B_VERTICAL)
1205 .Add(text)
1206 .AddGroup(B_HORIZONTAL)
1207 .AddGlue()
1208 .Add(ok)
1209 .Add(cancel)
1210 .End()
1211 .SetInsets(B_USE_DEFAULT_SPACING);
1212
1213 SetDefaultButton(ok);
1214 button = -1;
1215 text->MakeFocus();
1216 }
1217
Go()1218 bool ConnectDialog::Go() {
1219 Show();
1220
1221 while (button == -1) {
1222 usleep(1000);
1223 }
1224
1225 return (button == 0);
1226 }
1227
Position(BWindow * parent)1228 void ConnectDialog::Position(BWindow *parent) {
1229 BRect rect = (parent ? parent->Frame() : BScreen(this).Frame());
1230
1231 MoveTo((rect.right + rect.left) / 2 - 100, (rect.bottom + rect.top) / 2 - 50);
1232 }
1233
MessageReceived(BMessage * message)1234 void ConnectDialog::MessageReceived(BMessage *message) {
1235 switch(message->what) {
1236 case MSG_OK:
1237 button = 0;
1238 break;
1239
1240 case MSG_CANCEL:
1241 button = 1;
1242 break;
1243
1244 default:
1245 return;
1246 }
1247
1248 PostMessage(B_QUIT_REQUESTED);
1249 }
1250
beos_dialog_password(const char * msg)1251 char *beos_dialog_password(const char *msg) {
1252 ConnectDialog *dialog = new ConnectDialog();
1253 dialog->Position(dynamic_cast<BWindow*>(BLooper::LooperForThread(find_thread(NULL))));
1254
1255 if (dialog->Go()) {
1256 return strdup(dialog->text->Text());
1257 } else {
1258 return NULL;
1259 }
1260 }
1261
beos_dialog_okcancel(const char * msg)1262 int beos_dialog_okcancel(const char *msg) {
1263 BAlert *alert = new BAlert("Dialog", msg, "OK", "Cencel");
1264
1265 if (alert->Go() == 0) {
1266 return 1;
1267 } else {
1268 return 0;
1269 }
1270 }
1271
beos_dialog_alert(const char * msg)1272 int beos_dialog_alert(const char *msg) {
1273 BAlert *alert = new BAlert("Alert", msg, "OK");
1274
1275 alert->Go();
1276
1277 return 1;
1278 }
1279
beos_lock(void)1280 void beos_lock(void) {
1281 pthread_mutex_lock(&mutex);
1282 }
1283
beos_unlock(void)1284 void beos_unlock(void) {
1285 pthread_mutex_unlock(&mutex);
1286 }
1287