/* haiku.cpp * (c) 2007 François Revol * This file is a part of the Links program, released under GPL */ /* * GUI code */ /* * TODO: * - more paste handling ? * - more DnD (maybe check if in menu or not and prepend "g" ?) * - handle DnD of Net+ bookmarks */ #include "cfg.h" #ifdef GRDRV_HAIKU extern "C" { #include "links.h" } #undef B_ENTER #include #include #include #include #include #include #include #include #include #include #include #include //#define DBG(l...) fprintf(stderr, l); #define DBG(l...) {} /* #ifdef debug #undef debug #endif #define debug(x) #define fprintf(x, y) */ extern "C" struct graphics_driver haiku_driver; class LinksApplication : public BApplication { public: LinksApplication():BApplication("application/x-vnd.links"){} virtual bool QuitRequested(); }; class LinksView; class LinksWindow : public BWindow { public: LinksWindow(BRect r); ~LinksWindow(); virtual void FrameResized(float width, float height); virtual bool QuitRequested(); struct rect update_rect; int resized; LinksView *view; }; class LinksView : public BView { public: LinksView(LinksWindow *w); ~LinksView(); virtual void Draw(BRect r); virtual void MouseDown(BPoint p); virtual void MouseUp(BPoint p); virtual void MouseMoved(BPoint p, uint32 transit, const BMessage *dragmsg); virtual void KeyDown(const char *s, int32 numBytes); virtual void MessageReceived(BMessage *msg); LinksWindow *win; struct graphics_device *dev; void d_flush(); int flushing; int last_x, last_y; unsigned last_buttons; }; #define lv(dev) ((LinksView *)(dev)->driver_data) #define lock_dev(dev) do { if (!lv(dev)->win->Lock()) return; } while (0) #define lock_dev0(dev) do { if (!lv(dev)->win->Lock()) return 0; } while (0) #define unlock_dev(dev) do { lv(dev)->win->Unlock(); } while (0) static void be_get_size(struct graphics_device *dev); struct be_event { list_entry_1st BMessage *msg; struct graphics_device *dev; list_entry_last }; static struct list_head be_message_queue; static BLocker message_queue_lock; #define detach_and_pipe_message(d) do { \ BMessage *current = Looper()->DetachCurrentMessage(); \ if (current) { \ struct be_event *ev = (struct be_event *)malloc(sizeof(struct be_event));\ message_queue_lock.Lock(); \ if (ev && d) { \ int r; \ ev->msg = current; \ ev->dev = d; \ add_to_list_end(be_message_queue, ev); \ EINTRLOOP(r, write(wpipe, " ", 1)); \ } else { \ if (ev) free(ev); \ delete current; \ } \ message_queue_lock.Unlock(); \ } \ } while (0) static LinksApplication *be_links_app; static int msg_pipe[2]; static thread_id be_app_thread_id; #define rpipe (msg_pipe[0]) #define wpipe (msg_pipe[1]) #define small_color (sizeof(rgb_color) <= sizeof(long)) #define get_color32(c, rgb) rgb_color \ c((rgb_color){ \ static_cast((rgb >> 16) & 255), \ static_cast((rgb >> 8) & 255), \ static_cast(rgb & 255), \ 255}) static color_space be_cs_desktop, be_cs_bmp; static int be_x_size, be_y_size; static int be_win_x_size, be_win_y_size; static int be_win_x_pos, be_win_y_pos; bool LinksApplication::QuitRequested() { int i, n; n = CountWindows(); for (i = 0; i < n; i++) { BWindow *win = WindowAt(i); if (win) { win->PostMessage(B_QUIT_REQUESTED); } } return false; } LinksWindow::LinksWindow(BRect r):BWindow(r, "Links", B_DOCUMENT_WINDOW, 0) { DBG("LINKSWINDOW\n"); update_rect.x1 = 0; update_rect.x2 = 0; update_rect.y1 = 0; update_rect.y2 = 0; resized = 0; view = NULL; } LinksWindow::~LinksWindow() { view = NULL; DBG("~LINKSWINDOW\n"); } void LinksWindow::FrameResized(float width, float height) { message_queue_lock.Lock(); resized = 1; message_queue_lock.Unlock(); } bool LinksWindow::QuitRequested() { detach_and_pipe_message(view->dev); return false; } static void do_flush(void *p_dev) { struct graphics_device *dev = (struct graphics_device *)p_dev; LinksView *v = lv(dev); v->win->Lock(); v->win->Flush(); v->win->Unlock(); v->flushing = 0; } LinksView::LinksView(LinksWindow *w):BView(w->Bounds(), "Links", B_FOLLOW_ALL, B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE | B_NAVIGABLE) { DBG("LINKSVIEW\n"); (win = w)->AddChild(this); SetViewColor(B_TRANSPARENT_32_BIT); MakeFocus(); w->view = this; flushing = 0; last_x = last_y = 0; last_buttons = 0; } LinksView::~LinksView() { win->view = NULL; DBG("~LINKSVIEW\n"); } void LinksView::d_flush() { if (flushing) return; register_bottom_half(do_flush, this->dev); flushing = 1; } static void be_get_event(void *dummy) { struct be_event *ev; static char to_read[64]; int r; BMessage *msg; LinksView *view; LinksWindow *win; struct graphics_device *dev; EINTRLOOP(r, read(rpipe, to_read, sizeof to_read)); test_another_message: message_queue_lock.Lock(); ev = NULL; if (!list_empty(be_message_queue)) { ev = list_struct(be_message_queue.next, struct be_event); del_from_list(ev); } message_queue_lock.Unlock(); if (!ev) return; msg = ev->msg; dev = ev->dev; view = lv(dev); win = dynamic_cast(view->Window()); switch (msg->what) { case B_QUIT_REQUESTED: { dev->keyboard_handler(dev, KBD_CTRL_C, 0); break; } case _UPDATE_: { /*DBG("paint: %d %d %d %d\n", rr.x1, rr.x2, rr.y1, rr.y2);*/ struct rect rr; int resized; message_queue_lock.Lock(); rr = win->update_rect; win->update_rect.x1 = win->update_rect.x2 = win->update_rect.y1 = win->update_rect.y2 = 0; resized = win->resized; win->resized = 0; message_queue_lock.Unlock(); if (!resized) { if (is_rect_valid(&rr)) dev->redraw_handler(dev, &rr); } else { be_get_size(dev); dev->resize_handler(dev); } break; } case B_MOUSE_DOWN: { BPoint where; int32 buttons; int btn = B_LEFT; if (msg->FindInt32("buttons", &buttons) != B_OK) return; if (msg->FindPoint("where", &where) != B_OK) return; if (view) view->last_buttons = buttons; if (buttons & B_PRIMARY_MOUSE_BUTTON) btn = B_LEFT; else if (buttons & B_SECONDARY_MOUSE_BUTTON) btn = B_RIGHT; else if (buttons & B_TERTIARY_MOUSE_BUTTON) btn = B_MIDDLE; else if (buttons & (B_TERTIARY_MOUSE_BUTTON << 1)) btn = B_FOURTH; else if (buttons & (B_TERTIARY_MOUSE_BUTTON << 2)) btn = B_FIFTH; else if (buttons & (B_TERTIARY_MOUSE_BUTTON << 3)) btn = B_SIXTH; dev->mouse_handler(dev, view->last_x = (int)where.x, view->last_y = (int)where.y, B_DOWN | btn); break; } case B_MOUSE_UP: { BPoint where; int32 buttons; int btn; if (msg->FindInt32("buttons", &buttons) != B_OK) return; if (msg->FindPoint("where", &where) != B_OK) return; btn = B_LEFT; if (view->last_buttons & ~buttons & B_PRIMARY_MOUSE_BUTTON) btn = B_LEFT; else if (view->last_buttons & ~buttons & B_SECONDARY_MOUSE_BUTTON) btn = B_RIGHT; else if (view->last_buttons & ~buttons & B_TERTIARY_MOUSE_BUTTON) btn = B_MIDDLE; else if (view->last_buttons & ~buttons & (B_TERTIARY_MOUSE_BUTTON << 1)) btn = B_FOURTH; else if (view->last_buttons & ~buttons & (B_TERTIARY_MOUSE_BUTTON << 2)) btn = B_FIFTH; else if (view->last_buttons & ~buttons & (B_TERTIARY_MOUSE_BUTTON << 3)) btn = B_SIXTH; view->last_buttons = buttons; dev->mouse_handler(dev, view->last_x = (int)where.x, view->last_y = (int)where.y, B_UP | btn); break; } case B_MOUSE_MOVED: { BPoint where; int32 buttons; int btn = B_LEFT; if (msg->FindInt32("buttons", &buttons) != B_OK) return; if (msg->FindPoint("where", &where) != B_OK) return; if (buttons & B_PRIMARY_MOUSE_BUTTON) btn = B_LEFT; else if (buttons & B_SECONDARY_MOUSE_BUTTON) btn = B_RIGHT; else if (buttons & B_TERTIARY_MOUSE_BUTTON) btn = B_MIDDLE; else if (buttons & (B_TERTIARY_MOUSE_BUTTON << 1)) btn = B_FOURTH; else if (buttons & (B_TERTIARY_MOUSE_BUTTON << 2)) btn = B_FIFTH; else if (buttons & (B_TERTIARY_MOUSE_BUTTON << 3)) btn = B_SIXTH; dev->mouse_handler(dev, view->last_x = (int)where.x, view->last_y = (int)where.y, !buttons ? B_MOVE : B_DRAG | btn); break; } case B_KEY_DOWN: { int32 modifiers; const char *bytes; int c; int mods = 0; if (msg->FindInt32("modifiers", &modifiers) != B_OK) return; if (msg->FindString("bytes", &bytes) != B_OK) return; unsigned char buf[4] = { 0, 0, 0, 0 }; unsigned char *ss; /*fprintf(stderr, "bytes '%s' %x %x, modifiers '%x'\n", bytes, bytes[0], bytes[1], modifiers);*/ if (modifiers & (B_LEFT_CONTROL_KEY | B_RIGHT_CONTROL_KEY | B_LEFT_COMMAND_KEY | B_RIGHT_COMMAND_KEY)) { int32 raw; if (msg->FindInt32("raw_char", &raw) != B_OK) return; buf[0] = (unsigned char)raw; ss = buf; } else { ss = (unsigned char *)bytes; } GET_UTF_8(ss, c); switch (c) { case B_BACKSPACE: c = KBD_BS; break; case B_ENTER: c = KBD_ENTER; break; case B_SPACE: c = ' '; break; case B_TAB: c = KBD_TAB; break; case B_ESCAPE: c = KBD_ESC; break; case B_LEFT_ARROW: c = KBD_LEFT; break; case B_RIGHT_ARROW: c = KBD_RIGHT; break; case B_UP_ARROW: c = KBD_UP; break; case B_DOWN_ARROW: c = KBD_DOWN; break; case B_INSERT: c = KBD_INS; break; case B_DELETE: c = KBD_DEL; break; case B_HOME: c = KBD_HOME; break; case B_END: c = KBD_END; break; case B_PAGE_UP: c = KBD_PAGE_UP; break; case B_PAGE_DOWN: c = KBD_PAGE_DOWN; break; case B_FUNCTION_KEY: { int32 fn; if (msg->FindInt32("key", &fn) != B_OK) goto def; if (fn >= B_F1_KEY && fn <= B_F12_KEY) { c = KBD_F1 - (fn - B_F1_KEY); break; } goto def; } default: def: if (c < 32) c = 0; else modifiers &= ~(B_LEFT_SHIFT_KEY|B_RIGHT_SHIFT_KEY); break; } if (modifiers & (B_LEFT_SHIFT_KEY|B_RIGHT_SHIFT_KEY)) mods |= KBD_SHIFT; if (modifiers & (B_LEFT_CONTROL_KEY|B_RIGHT_CONTROL_KEY)) mods |= KBD_CTRL; if (modifiers & (B_LEFT_COMMAND_KEY|B_RIGHT_COMMAND_KEY)) mods |= KBD_ALT; if (c) dev->keyboard_handler(dev, c, mods); break; } case B_COPY: { dev->keyboard_handler(dev, KBD_COPY, 0); break; } case B_CUT: { dev->keyboard_handler(dev, KBD_CUT, 0); break; } case B_PASTE: { dev->keyboard_handler(dev, KBD_PASTE, 0); break; } case B_MOUSE_WHEEL_CHANGED: { float delta_x, delta_y; if (msg->FindFloat("be:wheel_delta_x", &delta_x) != B_OK) delta_x = 0; if (msg->FindFloat("be:wheel_delta_y", &delta_y) != B_OK) delta_y = 0; if (delta_y) dev->mouse_handler(dev, view->last_x, view->last_y, B_MOVE | (delta_y > 0 ? B_WHEELDOWN : B_WHEELUP)); if (delta_x) dev->mouse_handler(dev, view->last_x, view->last_y, B_MOVE | (delta_x < 0 ? B_WHEELLEFT : B_WHEELRIGHT)); break; } case B_SIMPLE_DATA: { entry_ref ref; unsigned char *string = NULL; const unsigned char *text_plain; ssize_t len; if (msg->FindRef("refs", &ref) == B_OK) { BPath path(&ref); if (path.InitCheck() == B_OK) { BFile f(path.Path(), B_READ_ONLY); BString url; if (f.InitCheck() == B_OK && f.ReadAttrString("META:url", &url) >= B_OK) { string = stracpy((const unsigned char *)url.String()); } else { unsigned char str[3072]; int r; string = stracpy((const unsigned char *)"file://"); EINTRLOOP(r, readlink(path.Path(), (char *)str, sizeof(str))); if (r < 0 || r >= (int)sizeof(str)) { add_to_strn(&string, (unsigned char *)path.Path()); } else if (str[0] == '/') { add_to_strn(&string, str); } else { unsigned char *rch; add_to_strn(&string, (unsigned char *)path.Path()); rch = (unsigned char *)strrchr((const char *)string, '/'); if (rch) rch[1] = 0; add_to_strn(&string, str); } } } } else if (msg->FindData("text/plain", B_MIME_TYPE, (const void **)&text_plain, &len) == B_OK) { string = memacpy(text_plain, len); } if (string) { dev->extra_handler(dev, EV_EXTRA_OPEN_URL, string); mem_free(string); } break; } case B_MIME_DATA: { const unsigned char *text_plain; ssize_t len; if (msg->FindData("text/plain", B_MIME_TYPE, (const void **)&text_plain, &len) == B_OK) { unsigned char *string = memacpy(text_plain, len); dev->extra_handler(dev, EV_EXTRA_OPEN_URL, string); mem_free(string); } break; } default: { msg->PrintToStream(); break; } } free(ev); delete msg; goto test_another_message; } static void be_get_size(struct graphics_device *dev) { BRect r; lock_dev(dev); r = lv(dev)->Bounds(); unlock_dev(dev); dev->size.x1 = dev->size.y1 = 0; dev->size.x2 = (int)r.Width() + 1; dev->size.y2 = (int)r.Height() + 1; } void LinksView::Draw(BRect r) { struct rect rr; rr.x1 = (int)r.left; rr.x2 = (int)r.right + 1; rr.y1 = (int)r.top; rr.y2 = (int)r.bottom + 1; message_queue_lock.Lock(); if (dev) unite_rect(&lv(dev)->win->update_rect, &lv(dev)->win->update_rect, &rr); message_queue_lock.Unlock(); detach_and_pipe_message(dev); } void LinksView::MouseDown(BPoint p) { SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS); detach_and_pipe_message(dev); } void LinksView::MouseUp(BPoint p) { detach_and_pipe_message(dev); } void LinksView::MouseMoved(BPoint p, uint32 transit, const BMessage *dragmsg) { message_queue_lock.Lock(); if (!list_empty(be_message_queue)) { struct be_event *ev = list_struct(be_message_queue.prev, struct be_event); if (ev->msg->what == B_MOUSE_MOVED) { del_from_list(ev); delete ev->msg; free(ev); } } message_queue_lock.Unlock(); detach_and_pipe_message(dev); } void LinksView::MessageReceived(BMessage *msg) { switch (msg->what) { case B_MOUSE_WHEEL_CHANGED: case B_COPY: case B_CUT: case B_PASTE: case B_SIMPLE_DATA: case B_MIME_DATA: detach_and_pipe_message(dev); break; default: //BView::MessageReceived(msg); break; } } void LinksView::KeyDown(const char *s, int32 numBytes) { detach_and_pipe_message(dev); } static int32 be_app_thread(void *p) { be_links_app->Lock(); be_links_app->Run(); delete be_links_app; return 0; } static unsigned char *be_init_driver(unsigned char *param, unsigned char *display) { init_list(be_message_queue); be_links_app = new LinksApplication(); if (!be_links_app) { return stracpy((unsigned char *)"Unable to allocate Application object.\n"); } if (c_pipe(msg_pipe)) { delete be_links_app; return stracpy((unsigned char *)"Could not create pipe.\n"); } set_nonblock(rpipe); set_nonblock(wpipe); set_handlers(rpipe, be_get_event, NULL, NULL); be_app_thread_id = spawn_thread(be_app_thread, "links_app", B_NORMAL_PRIORITY, NULL); resume_thread(be_app_thread_id); be_links_app->Unlock(); be_cs_desktop = B_NO_COLOR_SPACE; be_x_size = 640; be_y_size = 480; BScreen d; if (d.IsValid()) { be_cs_desktop = d.ColorSpace(); be_x_size = (int)d.Frame().Width() + 1; be_y_size = (int)d.Frame().Height() + 1; } be_win_y_size = be_y_size * 9 / 10; be_win_x_size = be_win_y_size; /* DBG("%d %d\n", be_x_size, be_y_size); DBG("%d %d\n", be_win_x_size, be_win_y_size); */ be_win_y_pos = (be_y_size - be_win_y_size) / 2; be_win_x_pos = be_x_size - be_win_x_size - be_win_y_pos; /*debug("depth: %d %d %d %d %d", be_cs_desktop, B_RGB15, B_RGB16, B_RGB24, B_RGB32);*/ be_cs_bmp = be_cs_desktop; /* - BeOS doesn't handle BView::DrawBitmap() with RGB24 */ switch (be_cs_bmp) { case B_RGB32: haiku_driver.depth = 0xc4; break; case B_RGB16: haiku_driver.depth = 0x82; break; case B_RGB15: haiku_driver.depth = 0x7a; break; default: be_cs_bmp = B_RGB32; haiku_driver.depth = 0xc4; break; } return NULL; } static void be_shutdown_driver() { status_t ret; int r; //debug((unsigned char *)"D"); //debug((unsigned char *)"DD"); be_links_app->PostMessage(_QUIT_); //debug((unsigned char *)"E"); wait_for_thread(be_app_thread_id, &ret); //debug((unsigned char *)"F"); set_handlers(rpipe, NULL, NULL, NULL); EINTRLOOP(r, close(rpipe)); EINTRLOOP(r, close(wpipe)); } static struct graphics_device *be_init_device() { LinksView *view; LinksWindow *win; struct graphics_device *dev = (struct graphics_device *)mem_calloc(sizeof(struct graphics_device)); //debug((unsigned char *)"1"); 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)); be_win_x_pos += 28; if (be_win_x_pos + be_win_x_size > be_x_size) be_win_x_pos = 5; be_win_y_pos += 28; if (be_win_y_pos + be_win_y_size > be_y_size) be_win_y_pos = 29; //debug((unsigned char *)"2"); if (!win) { mem_free(dev); return NULL; } //debug((unsigned char *)"3"); view = new LinksView(win); if (!view) { delete win; mem_free(dev); return NULL; } view->dev = dev; dev->driver_data = view; be_get_size(dev); memcpy(&dev->clip, &dev->size, sizeof(struct rect)); //debug((unsigned char *)"4"); win->Show(); win->Lock(); view->MakeFocus(); win->Unlock(); //debug((unsigned char *)"5"); return dev; } static void be_shutdown_device(struct graphics_device *dev) { struct be_event *ev; struct list_head *lev; LinksWindow *win = lv(dev)->win; unregister_bottom_half(do_flush, dev); message_queue_lock.Lock(); lv(dev)->dev = NULL; foreachback(struct be_event, ev, lev, be_message_queue) { if (ev->dev == dev) { lev = lev->next; del_from_list(ev); delete ev->msg; free(ev); } } message_queue_lock.Unlock(); win->PostMessage(_QUIT_); mem_free(dev); } static unsigned char *be_get_af_unix_name(void) { return cast_uchar ""; } static void be_set_title(struct graphics_device *dev, unsigned char *title) { LinksWindow *win = lv(dev)->win; lock_dev(dev); win->SetTitle((const char *)title); lv(dev)->d_flush(); unlock_dev(dev); } static int be_get_empty_bitmap(struct bitmap *bmp) { bmp->data = NULL; bmp->flags = NULL; DBG("bmp\n"); //DBG("bmp (%d, %d) cs %08x\n", bmp->x, bmp->y, be_cs_bmp); BRect r(0, 0, bmp->x - 1, bmp->y - 1); retry: BBitmap *b = new BBitmap(r, /*B_RGB32*/be_cs_bmp); if (!b) { if (out_of_memory(0, NULL, 0)) goto retry; DBG("%s: error 1\n", __FUNCTION__); return -1; } if (!b->IsValid()) { delete b; DBG("%s: error 2\n", __FUNCTION__); return -1; } if (b->LockBits() < B_OK) { delete b; DBG("%s: error 3\n", __FUNCTION__); return -1; } bmp->data = b->Bits(); bmp->skip = b->BytesPerRow(); bmp->flags = b; //DBG("bmp: data %p, skip %d, flags %p\n", bmp->data, bmp->skip, bmp->flags); return 0; } static void be_register_bitmap(struct bitmap *bmp) { BBitmap *b = (BBitmap *)bmp->flags; if (b) b->UnlockBits(); } static void *be_prepare_strip(struct bitmap *bmp, int top, int lines) { DBG("preps\n"); BBitmap *b = (BBitmap *)bmp->flags; if (!b) return NULL; if (b->LockBits() < B_OK) return NULL; bmp->data = b->Bits(); bmp->skip = b->BytesPerRow(); return ((char *)bmp->data) + bmp->skip * top; } static void be_commit_strip(struct bitmap *bmp, int top, int lines) { BBitmap *b = (BBitmap *)bmp->flags; if (!b) return; b->UnlockBits(); } static void be_unregister_bitmap(struct bitmap *bmp) { DBG("unb\n"); BBitmap *b = (BBitmap *)bmp->flags; if (!b) return; delete b; } static void be_draw_bitmap(struct graphics_device *dev, struct bitmap *bmp, int x, int y) { DBG("drawb\n"); BBitmap *b = (BBitmap *)bmp->flags; if (!b) return; CLIP_DRAW_BITMAP lock_dev(dev); lv(dev)->DrawBitmap(b, b->Bounds(), BRect(x, y, x + bmp->x - 1, y + bmp->y - 1)); lv(dev)->d_flush(); unlock_dev(dev); } static long be_get_color(int rgb) { if (small_color) { get_color32(c, rgb); return *(long *)(void *)&c; } else return rgb & 0xffffff; } static void *color2void(long *color) { return (void *)color; } static void be_fill_area(struct graphics_device *dev, int x1, int y1, int x2, int y2, long color) { DBG("fill\n"); CLIP_FILL_AREA lock_dev(dev); if (small_color) lv(dev)->SetHighColor(*(rgb_color *)color2void(&color)); else lv(dev)->SetHighColor(get_color32(, color)); lv(dev)->FillRect(BRect(x1, y1, x2 - 1, y2 - 1)); lv(dev)->d_flush(); unlock_dev(dev); } static void be_draw_hline(struct graphics_device *dev, int x1, int y, int x2, long color) { DBG("hline\n"); CLIP_DRAW_HLINE lock_dev(dev); if (small_color) lv(dev)->SetHighColor(*(rgb_color *)color2void(&color)); else lv(dev)->SetHighColor(get_color32(, color)); lv(dev)->StrokeLine(BPoint(x1, y), BPoint(x2 - 1, y)); lv(dev)->d_flush(); unlock_dev(dev); } static void be_draw_vline(struct graphics_device *dev, int x, int y1, int y2, long color) { DBG("vline\n"); CLIP_DRAW_VLINE lock_dev(dev); if (small_color) lv(dev)->SetHighColor(*(rgb_color *)color2void(&color)); else lv(dev)->SetHighColor(get_color32(, color)); lv(dev)->StrokeLine(BPoint(x, y1), BPoint(x, y2 - 1)); lv(dev)->d_flush(); unlock_dev(dev); } static void be_scroll_redraws(struct graphics_device *dev, struct rect *r, int scx, int scy) { struct rect *e = &lv(dev)->win->update_rect; if (!is_rect_valid(e)) return; if (scx >= 0) { if (e->x2 > r->x1 && e->x2 < r->x2) { e->x2 += scx; if (e->x2 > r->x2) e->x2 = r->x2; } } else { if (e->x1 > r->x1 && e->x1 < r->x2) { e->x1 += scx; if (e->x1 < r->x1) e->x1 = r->x1; } } if (scy >= 0) { if (e->y2 > r->y1 && e->y2 < r->y2) { e->y2 += scy; if (e->y2 > r->y2) e->y2 = r->y2; } } else { if (e->y1 > r->y1 && e->y1 < r->y2) { e->y1 += scy; if (e->y1 < r->y1) e->y1 = r->y1; } } } static int be_scroll(struct graphics_device *dev, struct rect_set **ignore, int scx, int scy) { DBG("scroll\n"); lock_dev0(dev); lv(dev)->CopyBits( BRect( dev->clip.x1 - (scx < 0 ? scx : 0), dev->clip.y1 - (scy < 0 ? scy : 0), dev->clip.x2 - (scx >= 0 ? scx : 0) - 1, dev->clip.y2 - (scy >= 0 ? scy : 0) - 1), BRect( dev->clip.x1 + (scx >= 0 ? scx : 0), dev->clip.y1 + (scy >= 0 ? scy : 0), dev->clip.x2 + (scx < 0 ? scx : 0) - 1, dev->clip.y2 + (scy < 0 ? scy : 0) - 1) ); lv(dev)->d_flush(); be_scroll_redraws(dev, &dev->clip, scx, scy); unlock_dev(dev); return 1; } static void be_set_clip_area(struct graphics_device *dev) { DBG("setc\n"); lock_dev(dev); BRegion clip(BRect(dev->clip.x1, dev->clip.y1, dev->clip.x2 - 1, dev->clip.y2 - 1)); lv(dev)->ConstrainClippingRegion(&clip); unlock_dev(dev); } static void be_flush(struct graphics_device *dev) { unregister_bottom_half(do_flush, dev); do_flush(dev); } static unsigned char *be_get_clipboard_text(void) { unsigned char *ret = NULL; if (be_clipboard->Lock()) { BMessage *data = be_clipboard->Data(); if (data) { const char *text_plain; ssize_t len; if (data->FindData("text/plain", B_MIME_TYPE, (const void **)&text_plain, &len) == B_OK) { ret = memacpy((unsigned char *)text_plain, len); } } be_clipboard->Unlock(); } return ret; } static void be_set_clipboard_text(struct graphics_device *dev, unsigned char *text) { if (be_clipboard->Lock()) { be_clipboard->Clear(); BMessage* data = be_clipboard->Data(); if (data) { data->AddData("text/plain", B_MIME_TYPE, (const char *)text, strlen((const char *)text)); be_clipboard->Commit(); } be_clipboard->Unlock(); } } struct graphics_driver haiku_driver = { (unsigned char *)"haiku", be_init_driver, be_init_device, be_shutdown_device, be_shutdown_driver, NULL, NULL, NULL, be_get_af_unix_name, NULL, NULL, be_get_empty_bitmap, be_register_bitmap, be_prepare_strip, be_commit_strip, be_unregister_bitmap, be_draw_bitmap, be_get_color, be_fill_area, be_draw_hline, be_draw_vline, be_scroll, be_set_clip_area, be_flush, NULL, /* block */ NULL, /* unblock */ NULL, /* set_palette */ NULL, /* get_real_colors */ be_set_title, x_exec, /* exec */ be_set_clipboard_text, /* set_clipboard_text */ be_get_clipboard_text, /* get_clipboard_text */ 0, /* depth */ 0, 0, /* size */ GD_UNICODE_KEYS, /* flags */ NULL, /* param */ }; #endif /* GRDRV_HAIKU */