1 /* haiku.cpp
2 * (c) 2007 François Revol
3 * This file is a part of the Links program, released under GPL
4 */
5
6 /*
7 * GUI code
8 */
9
10 /*
11 * TODO:
12 * - more paste handling ?
13 * - more DnD (maybe check if in menu or not and prepend "g" ?)
14 * - handle DnD of Net+ bookmarks
15 */
16
17 #include "cfg.h"
18
19 #ifdef GRDRV_HAIKU
20
21 extern "C" {
22 #include "links.h"
23 }
24 #undef B_ENTER
25
26 #include <app/Application.h>
27 #include <app/Clipboard.h>
28 #include <interface/Bitmap.h>
29 #include <interface/Region.h>
30 #include <interface/Screen.h>
31 #include <interface/View.h>
32 #include <interface/Window.h>
33 #include <storage/Entry.h>
34 #include <storage/File.h>
35 #include <storage/Path.h>
36 #include <support/Locker.h>
37 #include <support/String.h>
38
39 //#define DBG(l...) fprintf(stderr, l);
40 #define DBG(l...) {}
41
42 /*
43 #ifdef debug
44 #undef debug
45 #endif
46 #define debug(x)
47 #define fprintf(x, y)
48 */
49
50 extern "C" struct graphics_driver haiku_driver;
51
52 class LinksApplication : public BApplication {
53 public:
LinksApplication()54 LinksApplication():BApplication("application/x-vnd.links"){}
55 virtual bool QuitRequested();
56 };
57
58 class LinksView;
59
60 class LinksWindow : public BWindow {
61 public:
62 LinksWindow(BRect r);
63 ~LinksWindow();
64 virtual void FrameResized(float width, float height);
65 virtual bool QuitRequested();
66 struct rect update_rect;
67 int resized;
68 LinksView *view;
69 };
70
71 class LinksView : public BView {
72 public:
73 LinksView(LinksWindow *w);
74 ~LinksView();
75 virtual void Draw(BRect r);
76 virtual void MouseDown(BPoint p);
77 virtual void MouseUp(BPoint p);
78 virtual void MouseMoved(BPoint p, uint32 transit, const BMessage *dragmsg);
79 virtual void KeyDown(const char *s, int32 numBytes);
80 virtual void MessageReceived(BMessage *msg);
81 LinksWindow *win;
82 struct graphics_device *dev;
83 void d_flush();
84 int flushing;
85 int last_x, last_y;
86 unsigned last_buttons;
87 };
88
89 #define lv(dev) ((LinksView *)(dev)->driver_data)
90
91 #define lock_dev(dev) do { if (!lv(dev)->win->Lock()) return; } while (0)
92 #define lock_dev0(dev) do { if (!lv(dev)->win->Lock()) return 0; } while (0)
93 #define unlock_dev(dev) do { lv(dev)->win->Unlock(); } while (0)
94
95 static void be_get_size(struct graphics_device *dev);
96
97 struct be_event {
98 list_entry_1st
99 BMessage *msg;
100 struct graphics_device *dev;
101 list_entry_last
102 };
103
104 static struct list_head be_message_queue;
105 static BLocker message_queue_lock;
106
107 #define detach_and_pipe_message(d) do { \
108 BMessage *current = Looper()->DetachCurrentMessage(); \
109 if (current) { \
110 struct be_event *ev = (struct be_event *)malloc(sizeof(struct be_event));\
111 message_queue_lock.Lock(); \
112 if (ev && d) { \
113 int r; \
114 ev->msg = current; \
115 ev->dev = d; \
116 add_to_list_end(be_message_queue, ev); \
117 EINTRLOOP(r, write(wpipe, " ", 1)); \
118 } else { \
119 if (ev) free(ev); \
120 delete current; \
121 } \
122 message_queue_lock.Unlock(); \
123 } \
124 } while (0)
125
126 static LinksApplication *be_links_app;
127
128 static int msg_pipe[2];
129
130 static thread_id be_app_thread_id;
131
132 #define rpipe (msg_pipe[0])
133 #define wpipe (msg_pipe[1])
134
135 #define small_color (sizeof(rgb_color) <= sizeof(long))
136 #define get_color32(c, rgb) rgb_color \
137 c((rgb_color){ \
138 static_cast<uint8>((rgb >> 16) & 255), \
139 static_cast<uint8>((rgb >> 8) & 255), \
140 static_cast<uint8>(rgb & 255), \
141 255})
142
143 static color_space be_cs_desktop, be_cs_bmp;
144
145 static int be_x_size, be_y_size;
146
147 static int be_win_x_size, be_win_y_size;
148 static int be_win_x_pos, be_win_y_pos;
149
QuitRequested()150 bool LinksApplication::QuitRequested()
151 {
152 int i, n;
153 n = CountWindows();
154 for (i = 0; i < n; i++) {
155 BWindow *win = WindowAt(i);
156 if (win) {
157 win->PostMessage(B_QUIT_REQUESTED);
158 }
159 }
160 return false;
161 }
162
LinksWindow(BRect r)163 LinksWindow::LinksWindow(BRect r):BWindow(r, "Links", B_DOCUMENT_WINDOW, 0)
164 {
165 DBG("LINKSWINDOW\n");
166 update_rect.x1 = 0;
167 update_rect.x2 = 0;
168 update_rect.y1 = 0;
169 update_rect.y2 = 0;
170 resized = 0;
171 view = NULL;
172 }
173
~LinksWindow()174 LinksWindow::~LinksWindow()
175 {
176 view = NULL;
177 DBG("~LINKSWINDOW\n");
178 }
179
FrameResized(float width,float height)180 void LinksWindow::FrameResized(float width, float height)
181 {
182 message_queue_lock.Lock();
183 resized = 1;
184 message_queue_lock.Unlock();
185 }
186
QuitRequested()187 bool LinksWindow::QuitRequested()
188 {
189 detach_and_pipe_message(view->dev);
190 return false;
191 }
192
do_flush(void * p_dev)193 static void do_flush(void *p_dev)
194 {
195 struct graphics_device *dev = (struct graphics_device *)p_dev;
196 LinksView *v = lv(dev);
197 v->win->Lock();
198 v->win->Flush();
199 v->win->Unlock();
200 v->flushing = 0;
201 }
202
LinksView(LinksWindow * w)203 LinksView::LinksView(LinksWindow *w):BView(w->Bounds(), "Links", B_FOLLOW_ALL, B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE | B_NAVIGABLE)
204 {
205 DBG("LINKSVIEW\n");
206 (win = w)->AddChild(this);
207 SetViewColor(B_TRANSPARENT_32_BIT);
208 MakeFocus();
209 w->view = this;
210 flushing = 0;
211 last_x = last_y = 0;
212 last_buttons = 0;
213 }
214
~LinksView()215 LinksView::~LinksView()
216 {
217 win->view = NULL;
218 DBG("~LINKSVIEW\n");
219 }
220
d_flush()221 void LinksView::d_flush()
222 {
223 if (flushing) return;
224 register_bottom_half(do_flush, this->dev);
225 flushing = 1;
226 }
227
be_get_event(void * dummy)228 static void be_get_event(void *dummy)
229 {
230 struct be_event *ev;
231 static char to_read[64];
232 int r;
233 BMessage *msg;
234 LinksView *view;
235 LinksWindow *win;
236 struct graphics_device *dev;
237
238 EINTRLOOP(r, read(rpipe, to_read, sizeof to_read));
239
240 test_another_message:
241
242 message_queue_lock.Lock();
243 ev = NULL;
244 if (!list_empty(be_message_queue)) {
245 ev = list_struct(be_message_queue.next, struct be_event);
246 del_from_list(ev);
247 }
248 message_queue_lock.Unlock();
249
250 if (!ev)
251 return;
252
253 msg = ev->msg;
254 dev = ev->dev;
255 view = lv(dev);
256 win = dynamic_cast<LinksWindow *>(view->Window());
257
258 switch (msg->what) {
259 case B_QUIT_REQUESTED: {
260 dev->keyboard_handler(dev, KBD_CTRL_C, 0);
261 break;
262 }
263 case _UPDATE_: {
264 /*DBG("paint: %d %d %d %d\n", rr.x1, rr.x2, rr.y1, rr.y2);*/
265 struct rect rr;
266 int resized;
267
268 message_queue_lock.Lock();
269 rr = win->update_rect;
270 win->update_rect.x1 =
271 win->update_rect.x2 =
272 win->update_rect.y1 =
273 win->update_rect.y2 = 0;
274 resized = win->resized;
275 win->resized = 0;
276 message_queue_lock.Unlock();
277
278 if (!resized) {
279 if (is_rect_valid(&rr))
280 dev->redraw_handler(dev, &rr);
281 } else {
282 be_get_size(dev);
283 dev->resize_handler(dev);
284 }
285 break;
286 }
287 case B_MOUSE_DOWN: {
288 BPoint where;
289 int32 buttons;
290 int btn = B_LEFT;
291 if (msg->FindInt32("buttons", &buttons) != B_OK)
292 return;
293 if (msg->FindPoint("where", &where) != B_OK)
294 return;
295 if (view) view->last_buttons = buttons;
296 if (buttons & B_PRIMARY_MOUSE_BUTTON)
297 btn = B_LEFT;
298 else if (buttons & B_SECONDARY_MOUSE_BUTTON)
299 btn = B_RIGHT;
300 else if (buttons & B_TERTIARY_MOUSE_BUTTON)
301 btn = B_MIDDLE;
302 else if (buttons & (B_TERTIARY_MOUSE_BUTTON << 1))
303 btn = B_FOURTH;
304 else if (buttons & (B_TERTIARY_MOUSE_BUTTON << 2))
305 btn = B_FIFTH;
306 else if (buttons & (B_TERTIARY_MOUSE_BUTTON << 3))
307 btn = B_SIXTH;
308 dev->mouse_handler(dev, view->last_x = (int)where.x, view->last_y = (int)where.y, B_DOWN | btn);
309 break;
310 }
311 case B_MOUSE_UP: {
312 BPoint where;
313 int32 buttons;
314 int btn;
315 if (msg->FindInt32("buttons", &buttons) != B_OK)
316 return;
317 if (msg->FindPoint("where", &where) != B_OK)
318 return;
319 btn = B_LEFT;
320 if (view->last_buttons & ~buttons & B_PRIMARY_MOUSE_BUTTON)
321 btn = B_LEFT;
322 else if (view->last_buttons & ~buttons & B_SECONDARY_MOUSE_BUTTON)
323 btn = B_RIGHT;
324 else if (view->last_buttons & ~buttons & B_TERTIARY_MOUSE_BUTTON)
325 btn = B_MIDDLE;
326 else if (view->last_buttons & ~buttons & (B_TERTIARY_MOUSE_BUTTON << 1))
327 btn = B_FOURTH;
328 else if (view->last_buttons & ~buttons & (B_TERTIARY_MOUSE_BUTTON << 2))
329 btn = B_FIFTH;
330 else if (view->last_buttons & ~buttons & (B_TERTIARY_MOUSE_BUTTON << 3))
331 btn = B_SIXTH;
332 view->last_buttons = buttons;
333 dev->mouse_handler(dev, view->last_x = (int)where.x, view->last_y = (int)where.y, B_UP | btn);
334 break;
335 }
336 case B_MOUSE_MOVED: {
337 BPoint where;
338 int32 buttons;
339 int btn = B_LEFT;
340 if (msg->FindInt32("buttons", &buttons) != B_OK)
341 return;
342 if (msg->FindPoint("where", &where) != B_OK)
343 return;
344 if (buttons & B_PRIMARY_MOUSE_BUTTON)
345 btn = B_LEFT;
346 else if (buttons & B_SECONDARY_MOUSE_BUTTON)
347 btn = B_RIGHT;
348 else if (buttons & B_TERTIARY_MOUSE_BUTTON)
349 btn = B_MIDDLE;
350 else if (buttons & (B_TERTIARY_MOUSE_BUTTON << 1))
351 btn = B_FOURTH;
352 else if (buttons & (B_TERTIARY_MOUSE_BUTTON << 2))
353 btn = B_FIFTH;
354 else if (buttons & (B_TERTIARY_MOUSE_BUTTON << 3))
355 btn = B_SIXTH;
356 dev->mouse_handler(dev, view->last_x = (int)where.x, view->last_y = (int)where.y, !buttons ? B_MOVE : B_DRAG | btn);
357 break;
358 }
359 case B_KEY_DOWN: {
360 int32 modifiers;
361 const char *bytes;
362 int c;
363 int mods = 0;
364 if (msg->FindInt32("modifiers", &modifiers) != B_OK)
365 return;
366 if (msg->FindString("bytes", &bytes) != B_OK)
367 return;
368 unsigned char buf[4] = { 0, 0, 0, 0 };
369 unsigned char *ss;
370 /*fprintf(stderr, "bytes '%s' %x %x, modifiers '%x'\n", bytes, bytes[0], bytes[1], modifiers);*/
371 if (modifiers & (B_LEFT_CONTROL_KEY | B_RIGHT_CONTROL_KEY | B_LEFT_COMMAND_KEY | B_RIGHT_COMMAND_KEY)) {
372 int32 raw;
373 if (msg->FindInt32("raw_char", &raw) != B_OK)
374 return;
375 buf[0] = (unsigned char)raw;
376 ss = buf;
377 } else {
378 ss = (unsigned char *)bytes;
379 }
380
381 GET_UTF_8(ss, c);
382 switch (c) {
383 case B_BACKSPACE: c = KBD_BS; break;
384 case B_ENTER: c = KBD_ENTER; break;
385 case B_SPACE: c = ' '; break;
386 case B_TAB: c = KBD_TAB; break;
387 case B_ESCAPE: c = KBD_ESC; break;
388 case B_LEFT_ARROW: c = KBD_LEFT; break;
389 case B_RIGHT_ARROW: c = KBD_RIGHT; break;
390 case B_UP_ARROW: c = KBD_UP; break;
391 case B_DOWN_ARROW: c = KBD_DOWN; break;
392 case B_INSERT: c = KBD_INS; break;
393 case B_DELETE: c = KBD_DEL; break;
394 case B_HOME: c = KBD_HOME; break;
395 case B_END: c = KBD_END; break;
396 case B_PAGE_UP: c = KBD_PAGE_UP; break;
397 case B_PAGE_DOWN: c = KBD_PAGE_DOWN; break;
398 case B_FUNCTION_KEY: {
399 int32 fn;
400 if (msg->FindInt32("key", &fn) != B_OK)
401 goto def;
402 if (fn >= B_F1_KEY && fn <= B_F12_KEY) {
403 c = KBD_F1 - (fn - B_F1_KEY);
404 break;
405 }
406 goto def;
407 }
408 default:
409 def:
410 if (c < 32)
411 c = 0;
412 else modifiers &= ~(B_LEFT_SHIFT_KEY|B_RIGHT_SHIFT_KEY);
413 break;
414 }
415 if (modifiers & (B_LEFT_SHIFT_KEY|B_RIGHT_SHIFT_KEY))
416 mods |= KBD_SHIFT;
417 if (modifiers & (B_LEFT_CONTROL_KEY|B_RIGHT_CONTROL_KEY))
418 mods |= KBD_CTRL;
419 if (modifiers & (B_LEFT_COMMAND_KEY|B_RIGHT_COMMAND_KEY))
420 mods |= KBD_ALT;
421 if (c) dev->keyboard_handler(dev, c, mods);
422 break;
423 }
424 case B_COPY: {
425 dev->keyboard_handler(dev, KBD_COPY, 0);
426 break;
427 }
428 case B_CUT: {
429 dev->keyboard_handler(dev, KBD_CUT, 0);
430 break;
431 }
432 case B_PASTE: {
433 dev->keyboard_handler(dev, KBD_PASTE, 0);
434 break;
435 }
436 case B_MOUSE_WHEEL_CHANGED: {
437 float delta_x, delta_y;
438 if (msg->FindFloat("be:wheel_delta_x", &delta_x) != B_OK)
439 delta_x = 0;
440 if (msg->FindFloat("be:wheel_delta_y", &delta_y) != B_OK)
441 delta_y = 0;
442 if (delta_y) dev->mouse_handler(dev, view->last_x, view->last_y, B_MOVE | (delta_y > 0 ? B_WHEELDOWN : B_WHEELUP));
443 if (delta_x) dev->mouse_handler(dev, view->last_x, view->last_y, B_MOVE | (delta_x < 0 ? B_WHEELLEFT : B_WHEELRIGHT));
444 break;
445 }
446 case B_SIMPLE_DATA: {
447 entry_ref ref;
448 unsigned char *string = NULL;
449 const unsigned char *text_plain;
450 ssize_t len;
451 if (msg->FindRef("refs", &ref) == B_OK) {
452 BPath path(&ref);
453 if (path.InitCheck() == B_OK) {
454 BFile f(path.Path(), B_READ_ONLY);
455 BString url;
456 if (f.InitCheck() == B_OK && f.ReadAttrString("META:url", &url) >= B_OK) {
457 string = stracpy((const unsigned char *)url.String());
458 } else {
459 unsigned char str[3072];
460 int r;
461
462 string = stracpy((const unsigned char *)"file://");
463
464 EINTRLOOP(r, readlink(path.Path(), (char *)str, sizeof(str)));
465 if (r < 0 || r >= (int)sizeof(str)) {
466 add_to_strn(&string, (unsigned char *)path.Path());
467 } else if (str[0] == '/') {
468 add_to_strn(&string, str);
469 } else {
470 unsigned char *rch;
471 add_to_strn(&string, (unsigned char *)path.Path());
472 rch = (unsigned char *)strrchr((const char *)string, '/');
473 if (rch)
474 rch[1] = 0;
475 add_to_strn(&string, str);
476 }
477 }
478 }
479 } else if (msg->FindData("text/plain", B_MIME_TYPE, (const void **)&text_plain, &len) == B_OK) {
480 string = memacpy(text_plain, len);
481 }
482 if (string) {
483 dev->extra_handler(dev, EV_EXTRA_OPEN_URL, string);
484 mem_free(string);
485 }
486 break;
487 }
488 case B_MIME_DATA: {
489 const unsigned char *text_plain;
490 ssize_t len;
491 if (msg->FindData("text/plain", B_MIME_TYPE, (const void **)&text_plain, &len) == B_OK) {
492 unsigned char *string = memacpy(text_plain, len);
493 dev->extra_handler(dev, EV_EXTRA_OPEN_URL, string);
494 mem_free(string);
495 }
496 break;
497 }
498 default: {
499 msg->PrintToStream();
500 break;
501 }
502 }
503 free(ev);
504 delete msg;
505
506 goto test_another_message;
507 }
508
be_get_size(struct graphics_device * dev)509 static void be_get_size(struct graphics_device *dev)
510 {
511 BRect r;
512 lock_dev(dev);
513 r = lv(dev)->Bounds();
514 unlock_dev(dev);
515 dev->size.x1 = dev->size.y1 = 0;
516 dev->size.x2 = (int)r.Width() + 1;
517 dev->size.y2 = (int)r.Height() + 1;
518 }
519
Draw(BRect r)520 void LinksView::Draw(BRect r)
521 {
522 struct rect rr;
523 rr.x1 = (int)r.left;
524 rr.x2 = (int)r.right + 1;
525 rr.y1 = (int)r.top;
526 rr.y2 = (int)r.bottom + 1;
527 message_queue_lock.Lock();
528 if (dev)
529 unite_rect(&lv(dev)->win->update_rect, &lv(dev)->win->update_rect, &rr);
530 message_queue_lock.Unlock();
531 detach_and_pipe_message(dev);
532 }
533
534
MouseDown(BPoint p)535 void LinksView::MouseDown(BPoint p)
536 {
537 SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS);
538 detach_and_pipe_message(dev);
539 }
540
MouseUp(BPoint p)541 void LinksView::MouseUp(BPoint p)
542 {
543 detach_and_pipe_message(dev);
544 }
545
MouseMoved(BPoint p,uint32 transit,const BMessage * dragmsg)546 void LinksView::MouseMoved(BPoint p, uint32 transit, const BMessage *dragmsg)
547 {
548 message_queue_lock.Lock();
549 if (!list_empty(be_message_queue)) {
550 struct be_event *ev = list_struct(be_message_queue.prev, struct be_event);
551 if (ev->msg->what == B_MOUSE_MOVED) {
552 del_from_list(ev);
553 delete ev->msg;
554 free(ev);
555 }
556 }
557 message_queue_lock.Unlock();
558 detach_and_pipe_message(dev);
559 }
560
MessageReceived(BMessage * msg)561 void LinksView::MessageReceived(BMessage *msg)
562 {
563 switch (msg->what) {
564 case B_MOUSE_WHEEL_CHANGED:
565 case B_COPY:
566 case B_CUT:
567 case B_PASTE:
568 case B_SIMPLE_DATA:
569 case B_MIME_DATA:
570 detach_and_pipe_message(dev);
571 break;
572 default:
573 //BView::MessageReceived(msg);
574 break;
575 }
576 }
577
KeyDown(const char * s,int32 numBytes)578 void LinksView::KeyDown(const char *s, int32 numBytes)
579 {
580 detach_and_pipe_message(dev);
581 }
582
be_app_thread(void * p)583 static int32 be_app_thread(void *p)
584 {
585 be_links_app->Lock();
586 be_links_app->Run();
587 delete be_links_app;
588 return 0;
589 }
590
be_init_driver(unsigned char * param,unsigned char * display)591 static unsigned char *be_init_driver(unsigned char *param, unsigned char *display)
592 {
593 init_list(be_message_queue);
594 be_links_app = new LinksApplication();
595 if (!be_links_app) {
596 return stracpy((unsigned char *)"Unable to allocate Application object.\n");
597 }
598 if (c_pipe(msg_pipe)) {
599 delete be_links_app;
600 return stracpy((unsigned char *)"Could not create pipe.\n");
601 }
602 set_nonblock(rpipe);
603 set_nonblock(wpipe);
604 set_handlers(rpipe, be_get_event, NULL, NULL);
605 be_app_thread_id = spawn_thread(be_app_thread, "links_app", B_NORMAL_PRIORITY, NULL);
606 resume_thread(be_app_thread_id);
607 be_links_app->Unlock();
608 be_cs_desktop = B_NO_COLOR_SPACE;
609 be_x_size = 640;
610 be_y_size = 480;
611 BScreen d;
612 if (d.IsValid()) {
613 be_cs_desktop = d.ColorSpace();
614 be_x_size = (int)d.Frame().Width() + 1;
615 be_y_size = (int)d.Frame().Height() + 1;
616 }
617 be_win_y_size = be_y_size * 9 / 10;
618 be_win_x_size = be_win_y_size;
619 /*
620 DBG("%d %d\n", be_x_size, be_y_size);
621 DBG("%d %d\n", be_win_x_size, be_win_y_size);
622 */
623 be_win_y_pos = (be_y_size - be_win_y_size) / 2;
624 be_win_x_pos = be_x_size - be_win_x_size - be_win_y_pos;
625 /*debug("depth: %d %d %d %d %d", be_cs_desktop, B_RGB15, B_RGB16, B_RGB24, B_RGB32);*/
626 be_cs_bmp = be_cs_desktop;
627 /* - BeOS doesn't handle BView::DrawBitmap() with RGB24 */
628 switch (be_cs_bmp) {
629 case B_RGB32:
630 haiku_driver.depth = 0xc4;
631 break;
632 case B_RGB16:
633 haiku_driver.depth = 0x82;
634 break;
635 case B_RGB15:
636 haiku_driver.depth = 0x7a;
637 break;
638 default:
639 be_cs_bmp = B_RGB32;
640 haiku_driver.depth = 0xc4;
641 break;
642 }
643 return NULL;
644 }
645
be_shutdown_driver()646 static void be_shutdown_driver()
647 {
648 status_t ret;
649 int r;
650 //debug((unsigned char *)"D");
651 //debug((unsigned char *)"DD");
652 be_links_app->PostMessage(_QUIT_);
653 //debug((unsigned char *)"E");
654 wait_for_thread(be_app_thread_id, &ret);
655 //debug((unsigned char *)"F");
656 set_handlers(rpipe, NULL, NULL, NULL);
657 EINTRLOOP(r, close(rpipe));
658 EINTRLOOP(r, close(wpipe));
659 }
660
be_init_device()661 static struct graphics_device *be_init_device()
662 {
663 LinksView *view;
664 LinksWindow *win;
665 struct graphics_device *dev = (struct graphics_device *)mem_calloc(sizeof(struct graphics_device));
666 //debug((unsigned char *)"1");
667 win = new LinksWindow(BRect(be_win_x_pos, be_win_y_pos, be_win_x_pos + be_win_x_size, be_win_y_pos + be_win_y_size));
668 be_win_x_pos += 28;
669 if (be_win_x_pos + be_win_x_size > be_x_size)
670 be_win_x_pos = 5;
671 be_win_y_pos += 28;
672 if (be_win_y_pos + be_win_y_size > be_y_size)
673 be_win_y_pos = 29;
674 //debug((unsigned char *)"2");
675 if (!win) {
676 mem_free(dev);
677 return NULL;
678 }
679 //debug((unsigned char *)"3");
680 view = new LinksView(win);
681 if (!view) {
682 delete win;
683 mem_free(dev);
684 return NULL;
685 }
686 view->dev = dev;
687 dev->driver_data = view;
688 be_get_size(dev);
689 memcpy(&dev->clip, &dev->size, sizeof(struct rect));
690 //debug((unsigned char *)"4");
691 win->Show();
692 win->Lock();
693 view->MakeFocus();
694 win->Unlock();
695 //debug((unsigned char *)"5");
696 return dev;
697 }
698
be_shutdown_device(struct graphics_device * dev)699 static void be_shutdown_device(struct graphics_device *dev)
700 {
701 struct be_event *ev;
702 struct list_head *lev;
703 LinksWindow *win = lv(dev)->win;
704 unregister_bottom_half(do_flush, dev);
705
706 message_queue_lock.Lock();
707 lv(dev)->dev = NULL;
708 foreachback(struct be_event, ev, lev, be_message_queue) {
709 if (ev->dev == dev) {
710 lev = lev->next;
711 del_from_list(ev);
712 delete ev->msg;
713 free(ev);
714 }
715 }
716 message_queue_lock.Unlock();
717
718 win->PostMessage(_QUIT_);
719 mem_free(dev);
720 }
721
be_get_af_unix_name(void)722 static unsigned char *be_get_af_unix_name(void)
723 {
724 return cast_uchar "";
725 }
726
be_set_title(struct graphics_device * dev,unsigned char * title)727 static void be_set_title(struct graphics_device *dev, unsigned char *title)
728 {
729 LinksWindow *win = lv(dev)->win;
730 lock_dev(dev);
731 win->SetTitle((const char *)title);
732 lv(dev)->d_flush();
733 unlock_dev(dev);
734 }
735
be_get_empty_bitmap(struct bitmap * bmp)736 static int be_get_empty_bitmap(struct bitmap *bmp)
737 {
738 bmp->data = NULL;
739 bmp->flags = NULL;
740 DBG("bmp\n");
741 //DBG("bmp (%d, %d) cs %08x\n", bmp->x, bmp->y, be_cs_bmp);
742 BRect r(0, 0, bmp->x - 1, bmp->y - 1);
743 retry:
744 BBitmap *b = new BBitmap(r, /*B_RGB32*/be_cs_bmp);
745 if (!b) {
746 if (out_of_memory(0, NULL, 0))
747 goto retry;
748 DBG("%s: error 1\n", __FUNCTION__);
749 return -1;
750 }
751 if (!b->IsValid()) {
752 delete b;
753 DBG("%s: error 2\n", __FUNCTION__);
754 return -1;
755 }
756 if (b->LockBits() < B_OK) {
757 delete b;
758 DBG("%s: error 3\n", __FUNCTION__);
759 return -1;
760 }
761 bmp->data = b->Bits();
762 bmp->skip = b->BytesPerRow();
763 bmp->flags = b;
764 //DBG("bmp: data %p, skip %d, flags %p\n", bmp->data, bmp->skip, bmp->flags);
765 return 0;
766 }
767
be_register_bitmap(struct bitmap * bmp)768 static void be_register_bitmap(struct bitmap *bmp)
769 {
770 BBitmap *b = (BBitmap *)bmp->flags;
771 if (b)
772 b->UnlockBits();
773 }
774
be_prepare_strip(struct bitmap * bmp,int top,int lines)775 static void *be_prepare_strip(struct bitmap *bmp, int top, int lines)
776 {
777 DBG("preps\n");
778 BBitmap *b = (BBitmap *)bmp->flags;
779 if (!b)
780 return NULL;
781 if (b->LockBits() < B_OK)
782 return NULL;
783 bmp->data = b->Bits();
784 bmp->skip = b->BytesPerRow();
785 return ((char *)bmp->data) + bmp->skip * top;
786 }
787
be_commit_strip(struct bitmap * bmp,int top,int lines)788 static void be_commit_strip(struct bitmap *bmp, int top, int lines)
789 {
790 BBitmap *b = (BBitmap *)bmp->flags;
791 if (!b)
792 return;
793 b->UnlockBits();
794 }
795
be_unregister_bitmap(struct bitmap * bmp)796 static void be_unregister_bitmap(struct bitmap *bmp)
797 {
798 DBG("unb\n");
799 BBitmap *b = (BBitmap *)bmp->flags;
800 if (!b)
801 return;
802 delete b;
803 }
804
be_draw_bitmap(struct graphics_device * dev,struct bitmap * bmp,int x,int y)805 static void be_draw_bitmap(struct graphics_device *dev, struct bitmap *bmp, int x, int y)
806 {
807 DBG("drawb\n");
808 BBitmap *b = (BBitmap *)bmp->flags;
809 if (!b)
810 return;
811 CLIP_DRAW_BITMAP
812 lock_dev(dev);
813 lv(dev)->DrawBitmap(b, b->Bounds(), BRect(x, y, x + bmp->x - 1, y + bmp->y - 1));
814 lv(dev)->d_flush();
815 unlock_dev(dev);
816 }
817
be_get_color(int rgb)818 static long be_get_color(int rgb)
819 {
820 if (small_color) {
821 get_color32(c, rgb);
822 return *(long *)(void *)&c;
823 } else return rgb & 0xffffff;
824 }
825
color2void(long * color)826 static void *color2void(long *color)
827 {
828 return (void *)color;
829 }
830
be_fill_area(struct graphics_device * dev,int x1,int y1,int x2,int y2,long color)831 static void be_fill_area(struct graphics_device *dev, int x1, int y1, int x2, int y2, long color)
832 {
833 DBG("fill\n");
834 CLIP_FILL_AREA
835 lock_dev(dev);
836 if (small_color)
837 lv(dev)->SetHighColor(*(rgb_color *)color2void(&color));
838 else
839 lv(dev)->SetHighColor(get_color32(, color));
840 lv(dev)->FillRect(BRect(x1, y1, x2 - 1, y2 - 1));
841 lv(dev)->d_flush();
842 unlock_dev(dev);
843 }
844
be_draw_hline(struct graphics_device * dev,int x1,int y,int x2,long color)845 static void be_draw_hline(struct graphics_device *dev, int x1, int y, int x2, long color)
846 {
847 DBG("hline\n");
848 CLIP_DRAW_HLINE
849 lock_dev(dev);
850 if (small_color)
851 lv(dev)->SetHighColor(*(rgb_color *)color2void(&color));
852 else
853 lv(dev)->SetHighColor(get_color32(, color));
854 lv(dev)->StrokeLine(BPoint(x1, y), BPoint(x2 - 1, y));
855 lv(dev)->d_flush();
856 unlock_dev(dev);
857 }
858
be_draw_vline(struct graphics_device * dev,int x,int y1,int y2,long color)859 static void be_draw_vline(struct graphics_device *dev, int x, int y1, int y2, long color)
860 {
861 DBG("vline\n");
862 CLIP_DRAW_VLINE
863 lock_dev(dev);
864 if (small_color)
865 lv(dev)->SetHighColor(*(rgb_color *)color2void(&color));
866 else
867 lv(dev)->SetHighColor(get_color32(, color));
868 lv(dev)->StrokeLine(BPoint(x, y1), BPoint(x, y2 - 1));
869 lv(dev)->d_flush();
870 unlock_dev(dev);
871 }
872
be_scroll_redraws(struct graphics_device * dev,struct rect * r,int scx,int scy)873 static void be_scroll_redraws(struct graphics_device *dev, struct rect *r, int scx, int scy)
874 {
875 struct rect *e = &lv(dev)->win->update_rect;
876 if (!is_rect_valid(e))
877 return;
878 if (scx >= 0) {
879 if (e->x2 > r->x1 && e->x2 < r->x2) {
880 e->x2 += scx;
881 if (e->x2 > r->x2) e->x2 = r->x2;
882 }
883 } else {
884 if (e->x1 > r->x1 && e->x1 < r->x2) {
885 e->x1 += scx;
886 if (e->x1 < r->x1) e->x1 = r->x1;
887 }
888 }
889 if (scy >= 0) {
890 if (e->y2 > r->y1 && e->y2 < r->y2) {
891 e->y2 += scy;
892 if (e->y2 > r->y2) e->y2 = r->y2;
893 }
894 } else {
895 if (e->y1 > r->y1 && e->y1 < r->y2) {
896 e->y1 += scy;
897 if (e->y1 < r->y1) e->y1 = r->y1;
898 }
899 }
900 }
901
be_scroll(struct graphics_device * dev,struct rect_set ** ignore,int scx,int scy)902 static int be_scroll(struct graphics_device *dev, struct rect_set **ignore, int scx, int scy)
903 {
904 DBG("scroll\n");
905 lock_dev0(dev);
906 lv(dev)->CopyBits(
907 BRect( dev->clip.x1 - (scx < 0 ? scx : 0),
908 dev->clip.y1 - (scy < 0 ? scy : 0),
909 dev->clip.x2 - (scx >= 0 ? scx : 0) - 1,
910 dev->clip.y2 - (scy >= 0 ? scy : 0) - 1),
911 BRect( dev->clip.x1 + (scx >= 0 ? scx : 0),
912 dev->clip.y1 + (scy >= 0 ? scy : 0),
913 dev->clip.x2 + (scx < 0 ? scx : 0) - 1,
914 dev->clip.y2 + (scy < 0 ? scy : 0) - 1)
915 );
916 lv(dev)->d_flush();
917 be_scroll_redraws(dev, &dev->clip, scx, scy);
918 unlock_dev(dev);
919 return 1;
920 }
921
be_set_clip_area(struct graphics_device * dev)922 static void be_set_clip_area(struct graphics_device *dev)
923 {
924 DBG("setc\n");
925 lock_dev(dev);
926 BRegion clip(BRect(dev->clip.x1, dev->clip.y1, dev->clip.x2 - 1, dev->clip.y2 - 1));
927 lv(dev)->ConstrainClippingRegion(&clip);
928 unlock_dev(dev);
929 }
930
be_flush(struct graphics_device * dev)931 static void be_flush(struct graphics_device *dev)
932 {
933 unregister_bottom_half(do_flush, dev);
934 do_flush(dev);
935 }
936
be_get_clipboard_text(void)937 static unsigned char *be_get_clipboard_text(void)
938 {
939 unsigned char *ret = NULL;
940 if (be_clipboard->Lock()) {
941 BMessage *data = be_clipboard->Data();
942 if (data) {
943 const char *text_plain;
944 ssize_t len;
945 if (data->FindData("text/plain", B_MIME_TYPE, (const void **)&text_plain, &len) == B_OK) {
946 ret = memacpy((unsigned char *)text_plain, len);
947 }
948 }
949 be_clipboard->Unlock();
950 }
951 return ret;
952 }
953
be_set_clipboard_text(struct graphics_device * dev,unsigned char * text)954 static void be_set_clipboard_text(struct graphics_device *dev, unsigned char *text)
955 {
956 if (be_clipboard->Lock()) {
957 be_clipboard->Clear();
958 BMessage* data = be_clipboard->Data();
959 if (data) {
960 data->AddData("text/plain", B_MIME_TYPE, (const char *)text, strlen((const char *)text));
961 be_clipboard->Commit();
962 }
963 be_clipboard->Unlock();
964 }
965 }
966
967 struct graphics_driver haiku_driver = {
968 (unsigned char *)"haiku",
969 be_init_driver,
970 be_init_device,
971 be_shutdown_device,
972 be_shutdown_driver,
973 NULL,
974 NULL,
975 NULL,
976 be_get_af_unix_name,
977 NULL,
978 NULL,
979 be_get_empty_bitmap,
980 be_register_bitmap,
981 be_prepare_strip,
982 be_commit_strip,
983 be_unregister_bitmap,
984 be_draw_bitmap,
985 be_get_color,
986 be_fill_area,
987 be_draw_hline,
988 be_draw_vline,
989 be_scroll,
990 be_set_clip_area,
991 be_flush,
992 NULL, /* block */
993 NULL, /* unblock */
994 NULL, /* set_palette */
995 NULL, /* get_real_colors */
996 be_set_title,
997 x_exec, /* exec */
998 be_set_clipboard_text, /* set_clipboard_text */
999 be_get_clipboard_text, /* get_clipboard_text */
1000 0, /* depth */
1001 0, 0, /* size */
1002 GD_UNICODE_KEYS, /* flags */
1003 NULL, /* param */
1004 };
1005
1006 #endif /* GRDRV_HAIKU */
1007