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