static void __CDECL global_evnt_m1( WINDOW * win, short buff[8] ) { struct gui_window * gw = input_window; static bool prev_url = false; static short prev_x=0; static short prev_y=0; bool within = false; LGRECT urlbox, bwbox, sbbox; int nx, ny; if( gw == NULL) return; if( prev_x == evnt.mx && prev_y == evnt.my ){ return; } short ghandle = wind_find( evnt.mx, evnt.my ); if( input_window->root->handle->handle == ghandle ){ // The window found at x,y is an gui_window // and it's the input window. browser_get_rect( gw, BR_CONTENT, &bwbox ); if( evnt.mx > bwbox.g_x && evnt.mx < bwbox.g_x + bwbox.g_w && evnt.my > bwbox.g_y && evnt.my < bwbox.g_y + bwbox.g_h ){ within = true; browser_window_mouse_track( input_window->browser->bw, 0, evnt.mx - bwbox.g_x + gw->browser->scroll.current.x, evnt.my - bwbox.g_y + gw->browser->scroll.current.y ); } if( gw->root->toolbar && within == false ) { mt_CompGetLGrect(&app, gw->root->toolbar->url.comp, WF_WORKXYWH, &urlbox); if( (evnt.mx > urlbox.g_x && evnt.mx < urlbox.g_x + urlbox.g_w ) && (evnt.my > urlbox.g_y && evnt.my < + urlbox.g_y + urlbox.g_h )) { gem_set_cursor( &gem_cursors.ibeam ); prev_url = true; } else { if( prev_url ) { gem_set_cursor( &gem_cursors.arrow ); prev_url = false; } } } } else { gem_set_cursor( &gem_cursors.arrow ); prev_url = false; } prev_x = evnt.mx; prev_y = evnt.my; }
/* called back when movement in browser window */ static int fb_browser_window_move(fbtk_widget_t *widget, fbtk_callback_info *cbi) { browser_mouse_state mouse = 0; struct gui_window *gw = cbi->context; struct browser_widget_s *bwidget = fbtk_get_userpw(widget); float scale = browser_window_get_scale(gw->bw); int x = (cbi->x + bwidget->scrollx) / scale; int y = (cbi->y + bwidget->scrolly) / scale; if (gui_drag.state == GUI_DRAG_PRESSED && (abs(x - gui_drag.x) > 5 || abs(y - gui_drag.y) > 5)) { /* Drag started */ if (gui_drag.button == 1) { browser_window_mouse_click(gw->bw, BROWSER_MOUSE_DRAG_1, gui_drag.x, gui_drag.y); } else { browser_window_mouse_click(gw->bw, BROWSER_MOUSE_DRAG_2, gui_drag.x, gui_drag.y); } gui_drag.grabbed_pointer = fbtk_tgrab_pointer(widget); gui_drag.state = GUI_DRAG_DRAG; } if (gui_drag.state == GUI_DRAG_DRAG) { /* set up mouse state */ mouse |= BROWSER_MOUSE_DRAG_ON; if (gui_drag.button == 1) mouse |= BROWSER_MOUSE_HOLDING_1; else mouse |= BROWSER_MOUSE_HOLDING_2; } browser_window_mouse_track(gw->bw, mouse, x, y); return 0; }
void html_mouse_action(struct content *c, struct browser_window *bw, browser_mouse_state mouse, int x, int y) { html_content *html = (html_content *) c; enum { ACTION_NONE, ACTION_SUBMIT, ACTION_GO } action = ACTION_NONE; const char *title = 0; nsurl *url = 0; const char *target = 0; char status_buffer[200]; const char *status = 0; browser_pointer_shape pointer = BROWSER_POINTER_DEFAULT; bool imagemap = false; int box_x = 0, box_y = 0; int gadget_box_x = 0, gadget_box_y = 0; int html_object_pos_x = 0, html_object_pos_y = 0; int text_box_x = 0; struct box *url_box = 0; struct box *gadget_box = 0; struct box *text_box = 0; struct box *box; struct form_control *gadget = 0; hlcache_handle *object = NULL; struct box *html_object_box = NULL; struct browser_window *iframe = NULL; struct box *next_box; struct box *drag_candidate = NULL; struct scrollbar *scrollbar = NULL; plot_font_style_t fstyle; int scroll_mouse_x = 0, scroll_mouse_y = 0; int padding_left, padding_right, padding_top, padding_bottom; browser_drag_type drag_type = browser_window_get_drag_type(bw); union content_msg_data msg_data; struct dom_node *node = NULL; if (drag_type != DRAGGING_NONE && !mouse && html->visible_select_menu != NULL) { /* drag end: select menu */ form_select_mouse_drag_end(html->visible_select_menu, mouse, x, y); } if (html->visible_select_menu != NULL) { box = html->visible_select_menu->box; box_coords(box, &box_x, &box_y); box_x -= box->border[LEFT].width; box_y += box->height + box->border[BOTTOM].width + box->padding[BOTTOM] + box->padding[TOP]; status = form_select_mouse_action(html->visible_select_menu, mouse, x - box_x, y - box_y); if (status != NULL) { msg_data.explicit_status_text = status; content_broadcast(c, CONTENT_MSG_STATUS, msg_data); } else { int width, height; form_select_get_dimensions(html->visible_select_menu, &width, &height); html->visible_select_menu = NULL; browser_window_redraw_rect(bw, box_x, box_y, width, height); } return; } if (!mouse && html->scrollbar != NULL) { /* drag end: scrollbar */ html_overflow_scroll_drag_end(html->scrollbar, mouse, x, y); } if (html->scrollbar != NULL) { struct html_scrollbar_data *data = scrollbar_get_data(html->scrollbar); box = data->box; box_coords(box, &box_x, &box_y); if (scrollbar_is_horizontal(html->scrollbar)) { scroll_mouse_x = x - box_x ; scroll_mouse_y = y - (box_y + box->padding[TOP] + box->height + box->padding[BOTTOM] - SCROLLBAR_WIDTH); status = scrollbar_mouse_action(html->scrollbar, mouse, scroll_mouse_x, scroll_mouse_y); } else { scroll_mouse_x = x - (box_x + box->padding[LEFT] + box->width + box->padding[RIGHT] - SCROLLBAR_WIDTH); scroll_mouse_y = y - box_y; status = scrollbar_mouse_action(html->scrollbar, mouse, scroll_mouse_x, scroll_mouse_y); } msg_data.explicit_status_text = status; content_broadcast(c, CONTENT_MSG_STATUS, msg_data); return; } /* Content related drags handled by now */ browser_window_set_drag_type(bw, DRAGGING_NONE, NULL); /* search the box tree for a link, imagemap, form control, or * box with scrollbars */ box = html->layout; /* Consider the margins of the html page now */ box_x = box->margin[LEFT]; box_y = box->margin[TOP]; /* descend through visible boxes setting more specific values for: * box - deepest box at point * html_object_box - html object * html_object_pos_x - html object * html_object_pos_y - html object * object - non html object * iframe - iframe * url - href or imagemap * target - href or imagemap or gadget * url_box - href or imagemap * imagemap - imagemap * gadget - gadget * gadget_box - gadget * gadget_box_x - gadget * gadget_box_y - gadget * title - title * pointer * * drag_candidate - first box with scroll * padding_left - box with scroll * padding_right * padding_top * padding_bottom * scrollbar - inside padding box stops decent * scroll_mouse_x - inside padding box stops decent * scroll_mouse_y - inside padding box stops decent * * text_box - text box * text_box_x - text_box */ while ((next_box = box_at_point(box, x, y, &box_x, &box_y)) != NULL) { box = next_box; if ((box->style != NULL) && (css_computed_visibility(box->style) == CSS_VISIBILITY_HIDDEN)) { continue; } if (box->node != NULL) { node = box->node; } if (box->object) { if (content_get_type(box->object) == CONTENT_HTML) { html_object_box = box; html_object_pos_x = box_x; html_object_pos_y = box_y; } else { object = box->object; } } if (box->iframe) { iframe = box->iframe; } if (box->href) { url = box->href; target = box->target; url_box = box; } if (box->usemap) { url = imagemap_get(html, box->usemap, box_x, box_y, x, y, &target); if (url) { imagemap = true; url_box = box; } } if (box->gadget) { gadget = box->gadget; gadget_box = box; gadget_box_x = box_x; gadget_box_y = box_y; if (gadget->form) target = gadget->form->target; } if (box->title) { title = box->title; } pointer = get_pointer_shape(box, false); if ((box->scroll_x != NULL) || (box->scroll_y != NULL)) { if (drag_candidate == NULL) { drag_candidate = box; } padding_left = box_x + scrollbar_get_offset(box->scroll_x); padding_right = padding_left + box->padding[LEFT] + box->width + box->padding[RIGHT]; padding_top = box_y + scrollbar_get_offset(box->scroll_y); padding_bottom = padding_top + box->padding[TOP] + box->height + box->padding[BOTTOM]; if ((x > padding_left) && (x < padding_right) && (y > padding_top) && (y < padding_bottom)) { /* mouse inside padding box */ if ((box->scroll_y != NULL) && (x > (padding_right - SCROLLBAR_WIDTH))) { /* mouse above vertical box scroll */ scrollbar = box->scroll_y; scroll_mouse_x = x - (padding_right - SCROLLBAR_WIDTH); scroll_mouse_y = y - padding_top; break; } else if ((box->scroll_x != NULL) && (y > (padding_bottom - SCROLLBAR_WIDTH))) { /* mouse above horizontal box scroll */ scrollbar = box->scroll_x; scroll_mouse_x = x - padding_left; scroll_mouse_y = y - (padding_bottom - SCROLLBAR_WIDTH); break; } } } if (box->text && !box->object) { text_box = box; text_box_x = box_x; } } /* use of box_x, box_y, or content below this point is probably a * mistake; they will refer to the last box returned by box_at_point */ if (scrollbar) { status = scrollbar_mouse_action(scrollbar, mouse, scroll_mouse_x, scroll_mouse_y); pointer = BROWSER_POINTER_DEFAULT; } else if (gadget) { switch (gadget->type) { case GADGET_SELECT: status = messages_get("FormSelect"); pointer = BROWSER_POINTER_MENU; if (mouse & BROWSER_MOUSE_CLICK_1 && nsoption_bool(core_select_menu)) { html->visible_select_menu = gadget; form_open_select_menu(c, gadget, form_select_menu_callback, c); pointer = BROWSER_POINTER_DEFAULT; } else if (mouse & BROWSER_MOUSE_CLICK_1) gui_create_form_select_menu(bw, gadget); break; case GADGET_CHECKBOX: status = messages_get("FormCheckbox"); if (mouse & BROWSER_MOUSE_CLICK_1) { gadget->selected = !gadget->selected; html__redraw_a_box(html, gadget_box); } break; case GADGET_RADIO: status = messages_get("FormRadio"); if (mouse & BROWSER_MOUSE_CLICK_1) form_radio_set(html, gadget); break; case GADGET_IMAGE: if (mouse & BROWSER_MOUSE_CLICK_1) { gadget->data.image.mx = x - gadget_box_x; gadget->data.image.my = y - gadget_box_y; } /* drop through */ case GADGET_SUBMIT: if (gadget->form) { snprintf(status_buffer, sizeof status_buffer, messages_get("FormSubmit"), gadget->form->action); status = status_buffer; pointer = get_pointer_shape(gadget_box, false); if (mouse & (BROWSER_MOUSE_CLICK_1 | BROWSER_MOUSE_CLICK_2)) action = ACTION_SUBMIT; } else { status = messages_get("FormBadSubmit"); } break; case GADGET_TEXTAREA: status = messages_get("FormTextarea"); pointer = get_pointer_shape(gadget_box, false); if (mouse & (BROWSER_MOUSE_PRESS_1 | BROWSER_MOUSE_PRESS_2)) { if (text_box && selection_root(&html->sel) != gadget_box) selection_init(&html->sel, gadget_box); textinput_textarea_click(c, mouse, gadget_box, gadget_box_x, gadget_box_y, x - gadget_box_x, y - gadget_box_y); } if (text_box) { int pixel_offset; size_t idx; font_plot_style_from_css(text_box->style, &fstyle); nsfont.font_position_in_string(&fstyle, text_box->text, text_box->length, x - gadget_box_x - text_box->x, &idx, &pixel_offset); selection_click(&html->sel, mouse, text_box->byte_offset + idx); if (selection_dragging(&html->sel)) { browser_window_set_drag_type(bw, DRAGGING_SELECTION, NULL); status = messages_get("Selecting"); } } else if (mouse & BROWSER_MOUSE_PRESS_1) selection_clear(&html->sel, true); break; case GADGET_TEXTBOX: case GADGET_PASSWORD: status = messages_get("FormTextbox"); pointer = get_pointer_shape(gadget_box, false); if ((mouse & BROWSER_MOUSE_PRESS_1) && !(mouse & (BROWSER_MOUSE_MOD_1 | BROWSER_MOUSE_MOD_2))) { textinput_input_click(c, gadget_box, gadget_box_x, gadget_box_y, x - gadget_box_x, y - gadget_box_y); } if (text_box) { int pixel_offset; size_t idx; if (mouse & (BROWSER_MOUSE_DRAG_1 | BROWSER_MOUSE_DRAG_2)) selection_init(&html->sel, gadget_box); font_plot_style_from_css(text_box->style, &fstyle); nsfont.font_position_in_string(&fstyle, text_box->text, text_box->length, x - gadget_box_x - text_box->x, &idx, &pixel_offset); selection_click(&html->sel, mouse, text_box->byte_offset + idx); if (selection_dragging(&html->sel)) browser_window_set_drag_type(bw, DRAGGING_SELECTION, NULL); } else if (mouse & BROWSER_MOUSE_PRESS_1) selection_clear(&html->sel, true); break; case GADGET_HIDDEN: /* not possible: no box generated */ break; case GADGET_RESET: status = messages_get("FormReset"); break; case GADGET_FILE: status = messages_get("FormFile"); break; case GADGET_BUTTON: /* This gadget cannot be activated */ status = messages_get("FormButton"); break; } } else if (object && (mouse & BROWSER_MOUSE_MOD_2)) { if (mouse & BROWSER_MOUSE_DRAG_2) { msg_data.dragsave.type = CONTENT_SAVE_NATIVE; msg_data.dragsave.content = object; content_broadcast(c, CONTENT_MSG_DRAGSAVE, msg_data); } else if (mouse & BROWSER_MOUSE_DRAG_1) { msg_data.dragsave.type = CONTENT_SAVE_ORIG; msg_data.dragsave.content = object; content_broadcast(c, CONTENT_MSG_DRAGSAVE, msg_data); } /* \todo should have a drag-saving object msg */ } else if (iframe) { int pos_x, pos_y; float scale = browser_window_get_scale(bw); browser_window_get_position(iframe, false, &pos_x, &pos_y); pos_x /= scale; pos_y /= scale; if (mouse & BROWSER_MOUSE_CLICK_1 || mouse & BROWSER_MOUSE_CLICK_2) { browser_window_mouse_click(iframe, mouse, x - pos_x, y - pos_y); } else { browser_window_mouse_track(iframe, mouse, x - pos_x, y - pos_y); } } else if (html_object_box) { if (mouse & BROWSER_MOUSE_CLICK_1 || mouse & BROWSER_MOUSE_CLICK_2) { content_mouse_action(html_object_box->object, bw, mouse, x - html_object_pos_x, y - html_object_pos_y); } else { content_mouse_track(html_object_box->object, bw, mouse, x - html_object_pos_x, y - html_object_pos_y); } } else if (url) { if (title) { snprintf(status_buffer, sizeof status_buffer, "%s: %s", nsurl_access(url), title); status = status_buffer; } else status = nsurl_access(url); pointer = get_pointer_shape(url_box, imagemap); if (mouse & BROWSER_MOUSE_CLICK_1 && mouse & BROWSER_MOUSE_MOD_1) { /* force download of link */ browser_window_go_post(bw, nsurl_access(url), 0, 0, false, nsurl_access(content_get_url(c)), true, true, 0); } else if (mouse & BROWSER_MOUSE_CLICK_2 && mouse & BROWSER_MOUSE_MOD_1) { msg_data.savelink.url = nsurl_access(url); msg_data.savelink.title = title; content_broadcast(c, CONTENT_MSG_SAVELINK, msg_data); } else if (mouse & (BROWSER_MOUSE_CLICK_1 | BROWSER_MOUSE_CLICK_2)) action = ACTION_GO; } else { bool done = false; /* frame resizing */ if (browser_window_frame_resize_start(bw, mouse, x, y, &pointer)) { if (mouse & (BROWSER_MOUSE_DRAG_1 | BROWSER_MOUSE_DRAG_2)) { status = messages_get("FrameDrag"); } done = true; } /* if clicking in the main page, remove the selection from any * text areas */ if (!done) { struct box *layout = html->layout; if (mouse && (mouse < BROWSER_MOUSE_MOD_1) && selection_root(&html->sel) != layout) { selection_init(&html->sel, layout); } if (text_box) { int pixel_offset; size_t idx; font_plot_style_from_css(text_box->style, &fstyle); nsfont.font_position_in_string(&fstyle, text_box->text, text_box->length, x - text_box_x, &idx, &pixel_offset); if (selection_click(&html->sel, mouse, text_box->byte_offset + idx)) { /* key presses must be directed at the * main browser window, paste text * operations ignored */ if (selection_dragging(&html->sel)) { browser_window_set_drag_type(bw, DRAGGING_SELECTION, NULL); status = messages_get( "Selecting"); } done = true; } } else if (mouse & BROWSER_MOUSE_PRESS_1) selection_clear(&html->sel, true); } if (!done) { if (title) status = title; if (mouse & BROWSER_MOUSE_DRAG_1) { if (mouse & BROWSER_MOUSE_MOD_2) { msg_data.dragsave.type = CONTENT_SAVE_COMPLETE; msg_data.dragsave.content = NULL; content_broadcast(c, CONTENT_MSG_DRAGSAVE, msg_data); } else { if (drag_candidate == NULL) { browser_window_page_drag_start( bw, x, y); } else { html_box_drag_start( drag_candidate, x, y); } pointer = BROWSER_POINTER_MOVE; } } else if (mouse & BROWSER_MOUSE_DRAG_2) { if (mouse & BROWSER_MOUSE_MOD_2) { msg_data.dragsave.type = CONTENT_SAVE_SOURCE; msg_data.dragsave.content = NULL; content_broadcast(c, CONTENT_MSG_DRAGSAVE, msg_data); } else { if (drag_candidate == NULL) { browser_window_page_drag_start( bw, x, y); } else { html_box_drag_start( drag_candidate, x, y); } pointer = BROWSER_POINTER_MOVE; } } } if (mouse && mouse < BROWSER_MOUSE_MOD_1) { /* ensure key presses still act on the browser window */ browser_window_remove_caret(bw); } } if (!iframe && !html_object_box) { msg_data.explicit_status_text = status; content_broadcast(c, CONTENT_MSG_STATUS, msg_data); msg_data.pointer = pointer; content_broadcast(c, CONTENT_MSG_POINTER, msg_data); } /* fire dom click event */ if ((mouse & BROWSER_MOUSE_CLICK_1) || (mouse & BROWSER_MOUSE_CLICK_2)) { js_fire_event(html->jscontext, "click", html->document, node); } /* deferred actions that can cause this browser_window to be destroyed * and must therefore be done after set_status/pointer */ switch (action) { case ACTION_SUBMIT: form_submit(content_get_url(c), browser_window_find_target(bw, target, mouse), gadget->form, gadget); break; case ACTION_GO: browser_window_go(browser_window_find_target(bw, target, mouse), nsurl_access(url), nsurl_access(content_get_url(c)), true); break; case ACTION_NONE: break; } }
void nsbeos_dispatch_event(BMessage *message) { struct gui_window *gui = NULL; NSBrowserFrameView *view = NULL; struct beos_scaffolding *scaffold = NULL; NSBrowserWindow *window = NULL; //message->PrintToStream(); if (message->FindPointer("View", (void **)&view) < B_OK) view = NULL; if (message->FindPointer("gui_window", (void **)&gui) < B_OK) gui = NULL; if (message->FindPointer("Window", (void **)&window) < B_OK) window = NULL; if (message->FindPointer("scaffolding", (void **)&scaffold) < B_OK) scaffold = NULL; struct gui_window *z; for (z = window_list; z && gui && z != gui; z = z->next) continue; struct gui_window *y; for (y = window_list; y && scaffold && y->scaffold != scaffold; y = y->next) continue; if (gui && gui != z) { LOG(("discarding event for destroyed gui_window")); delete message; return; } if (scaffold && (!y || scaffold != y->scaffold)) { LOG(("discarding event for destroyed scaffolding")); delete message; return; } // messages for top-level if (scaffold) { LOG(("dispatching to top-level")); nsbeos_scaffolding_dispatch_event(scaffold, message); delete message; return; } //LOG(("processing message")); switch (message->what) { case B_QUIT_REQUESTED: // from the BApplication netsurf_quit = true; break; case B_ABOUT_REQUESTED: { nsbeos_about(gui); /* XXX: doesn't work yet! bug in rsrc:/ BString url("rsrc:/about.en.html,text/html"); browser_window_create(url.String(), NULL, NULL, true, false); */ break; } case _UPDATE_: if (gui && view) nsbeos_window_expose_event(view, gui, message); break; case B_MOUSE_MOVED: { if (gui == NULL) break; BPoint where; int32 mods; // where refers to Window coords !? // check be:view_where first if (message->FindPoint("be:view_where", &where) < B_OK) { if (message->FindPoint("where", &where) < B_OK) break; } if (message->FindInt32("modifiers", &mods) < B_OK) mods = 0; if (gui->mouse.state & BROWSER_MOUSE_PRESS_1) { /* Start button 1 drag */ browser_window_mouse_click(gui->bw, BROWSER_MOUSE_DRAG_1, gui->mouse.pressed_x, gui->mouse.pressed_y); /* Replace PRESS with HOLDING and declare drag in progress */ gui->mouse.state ^= (BROWSER_MOUSE_PRESS_1 | BROWSER_MOUSE_HOLDING_1); gui->mouse.state |= BROWSER_MOUSE_DRAG_ON; } else if (gui->mouse.state & BROWSER_MOUSE_PRESS_2) { /* Start button 2 drag */ browser_window_mouse_click(gui->bw, BROWSER_MOUSE_DRAG_2, gui->mouse.pressed_x, gui->mouse.pressed_y); /* Replace PRESS with HOLDING and declare drag in progress */ gui->mouse.state ^= (BROWSER_MOUSE_PRESS_2 | BROWSER_MOUSE_HOLDING_2); gui->mouse.state |= BROWSER_MOUSE_DRAG_ON; } bool shift = mods & B_SHIFT_KEY; bool ctrl = mods & B_CONTROL_KEY; /* Handle modifiers being removed */ if (gui->mouse.state & BROWSER_MOUSE_MOD_1 && !shift) gui->mouse.state ^= BROWSER_MOUSE_MOD_1; if (gui->mouse.state & BROWSER_MOUSE_MOD_2 && !ctrl) gui->mouse.state ^= BROWSER_MOUSE_MOD_2; browser_window_mouse_track(gui->bw, (browser_mouse_state)gui->mouse.state, (int)(where.x / gui->bw->scale), (int)(where.y / gui->bw->scale)); gui->last_x = (int)where.x; gui->last_y = (int)where.y; break; } case B_MOUSE_DOWN: { if (gui == NULL) break; BPoint where; int32 buttons; int32 mods; BPoint screenWhere; if (message->FindPoint("be:view_where", &where) < B_OK) { if (message->FindPoint("where", &where) < B_OK) break; } if (message->FindInt32("buttons", &buttons) < B_OK) break; if (message->FindPoint("screen_where", &screenWhere) < B_OK) break; if (message->FindInt32("modifiers", &mods) < B_OK) mods = 0; if (buttons & B_SECONDARY_MOUSE_BUTTON) { /* 2 == right button on BeOS */ nsbeos_scaffolding_popup_menu(gui->scaffold, screenWhere); break; } gui->mouse.state = BROWSER_MOUSE_PRESS_1; if (buttons & B_TERTIARY_MOUSE_BUTTON) /* 3 == middle button on BeOS */ gui->mouse.state = BROWSER_MOUSE_PRESS_2; if (mods & B_SHIFT_KEY) gui->mouse.state |= BROWSER_MOUSE_MOD_1; if (mods & B_CONTROL_KEY) gui->mouse.state |= BROWSER_MOUSE_MOD_2; gui->mouse.pressed_x = where.x / gui->bw->scale; gui->mouse.pressed_y = where.y / gui->bw->scale; // make sure the view is in focus if (view && view->LockLooper()) { if (!view->IsFocus()) view->MakeFocus(); view->UnlockLooper(); } browser_window_mouse_click(gui->bw, (browser_mouse_state)gui->mouse.state, gui->mouse.pressed_x, gui->mouse.pressed_y); break; } case B_MOUSE_UP: { if (gui == NULL) break; BPoint where; int32 buttons; int32 mods; BPoint screenWhere; if (message->FindPoint("be:view_where", &where) < B_OK) { if (message->FindPoint("where", &where) < B_OK) break; } if (message->FindInt32("buttons", &buttons) < B_OK) break; if (message->FindPoint("screen_where", &screenWhere) < B_OK) break; if (message->FindInt32("modifiers", &mods) < B_OK) mods = 0; /* If the mouse state is PRESS then we are waiting for a release to emit * a click event, otherwise just reset the state to nothing*/ if (gui->mouse.state & BROWSER_MOUSE_PRESS_1) gui->mouse.state ^= (BROWSER_MOUSE_PRESS_1 | BROWSER_MOUSE_CLICK_1); else if (gui->mouse.state & BROWSER_MOUSE_PRESS_2) gui->mouse.state ^= (BROWSER_MOUSE_PRESS_2 | BROWSER_MOUSE_CLICK_2); bool shift = mods & B_SHIFT_KEY; bool ctrl = mods & B_CONTROL_KEY; /* Handle modifiers being removed */ if (gui->mouse.state & BROWSER_MOUSE_MOD_1 && !shift) gui->mouse.state ^= BROWSER_MOUSE_MOD_1; if (gui->mouse.state & BROWSER_MOUSE_MOD_2 && !ctrl) gui->mouse.state ^= BROWSER_MOUSE_MOD_2; /* if (view && view->LockLooper()) { view->MakeFocus(); view->UnlockLooper(); } */ if (gui->mouse.state & (BROWSER_MOUSE_CLICK_1|BROWSER_MOUSE_CLICK_2)) browser_window_mouse_click(gui->bw, (browser_mouse_state)gui->mouse.state, where.x / gui->bw->scale, where.y / gui->bw->scale); else browser_window_mouse_track(gui->bw, (browser_mouse_state)0, where.x, where.y); gui->mouse.state = 0; break; } case B_KEY_DOWN: if (gui && view) nsbeos_window_keypress_event(view, gui, message); break; case B_VIEW_RESIZED: if (gui && view) nsbeos_window_resize_event(view, gui, message); break; case B_VIEW_MOVED: if (gui && view) nsbeos_window_moved_event(view, gui, message); break; case B_MOUSE_WHEEL_CHANGED: break; case B_UI_SETTINGS_CHANGED: nsbeos_update_system_ui_colors(); break; case 'nsLO': // login { BString url; BString realm; BString auth; if (message->FindString("URL", &url) < B_OK) break; if (message->FindString("Realm", &realm) < B_OK) break; if (message->FindString("Auth", &auth) < B_OK) break; //printf("login to '%s' with '%s'\n", url.String(), auth.String()); urldb_set_auth_details(url.String(), realm.String(), auth.String()); browser_window_go(gui->bw, url.String(), 0, true); break; } default: break; } delete message; }
static gboolean nsgtk_window_draw_event(GtkWidget *widget, cairo_t *cr, gpointer data) { struct gui_window *gw = data; struct gui_window *z; struct rect clip; struct redraw_context ctx = { .interactive = true, .background_images = true, .plot = &nsgtk_plotters }; double x1; double y1; double x2; double y2; assert(gw); assert(gw->bw); for (z = window_list; z && z != gw; z = z->next) continue; assert(z); assert(GTK_WIDGET(gw->layout) == widget); current_widget = (GtkWidget *)gw->layout; current_cr = cr; cairo_clip_extents(cr, &x1, &y1, &x2, &y2); clip.x0 = x1; clip.y0 = y1; clip.x1 = x2; clip.y1 = y2; browser_window_redraw(gw->bw, 0, 0, &clip, &ctx); if (gw->careth != 0) { nsgtk_plot_caret(gw->caretx, gw->carety, gw->careth); } current_widget = NULL; return FALSE; } #else static gboolean nsgtk_window_draw_event(GtkWidget *widget, GdkEventExpose *event, gpointer data) { struct gui_window *gw = data; struct gui_window *z; struct rect clip; struct redraw_context ctx = { .interactive = true, .background_images = true, .plot = &nsgtk_plotters }; assert(gw); assert(gw->bw); for (z = window_list; z && z != gw; z = z->next) continue; assert(z); assert(GTK_WIDGET(gw->layout) == widget); current_widget = (GtkWidget *)gw->layout; current_cr = gdk_cairo_create(nsgtk_layout_get_bin_window(gw->layout)); clip.x0 = event->area.x; clip.y0 = event->area.y; clip.x1 = event->area.x + event->area.width; clip.y1 = event->area.y + event->area.height; browser_window_redraw(gw->bw, 0, 0, &clip, &ctx); if (gw->careth != 0) { nsgtk_plot_caret(gw->caretx, gw->carety, gw->careth); } cairo_destroy(current_cr); current_widget = NULL; return FALSE; } #endif static gboolean nsgtk_window_motion_notify_event(GtkWidget *widget, GdkEventMotion *event, gpointer data) { struct gui_window *g = data; bool shift = event->state & GDK_SHIFT_MASK; bool ctrl = event->state & GDK_CONTROL_MASK; if ((abs(event->x - g->last_x) < 5) && (abs(event->y - g->last_y) < 5)) { /* Mouse hasn't moved far enough from press coordinate for this * to be considered a drag. */ return FALSE; } else { /* This is a drag, ensure it's always treated as such, even if * we drag back over the press location */ g->last_x = INT_MIN; g->last_y = INT_MIN; } if (g->mouse.state & BROWSER_MOUSE_PRESS_1) { /* Start button 1 drag */ browser_window_mouse_click(g->bw, BROWSER_MOUSE_DRAG_1, g->mouse.pressed_x, g->mouse.pressed_y); /* Replace PRESS with HOLDING and declare drag in progress */ g->mouse.state ^= (BROWSER_MOUSE_PRESS_1 | BROWSER_MOUSE_HOLDING_1); g->mouse.state |= BROWSER_MOUSE_DRAG_ON; } else if (g->mouse.state & BROWSER_MOUSE_PRESS_2) { /* Start button 2 drag */ browser_window_mouse_click(g->bw, BROWSER_MOUSE_DRAG_2, g->mouse.pressed_x, g->mouse.pressed_y); /* Replace PRESS with HOLDING and declare drag in progress */ g->mouse.state ^= (BROWSER_MOUSE_PRESS_2 | BROWSER_MOUSE_HOLDING_2); g->mouse.state |= BROWSER_MOUSE_DRAG_ON; } /* Handle modifiers being removed */ if (g->mouse.state & BROWSER_MOUSE_MOD_1 && !shift) g->mouse.state ^= BROWSER_MOUSE_MOD_1; if (g->mouse.state & BROWSER_MOUSE_MOD_2 && !ctrl) g->mouse.state ^= BROWSER_MOUSE_MOD_2; browser_window_mouse_track(g->bw, g->mouse.state, event->x / g->bw->scale, event->y / g->bw->scale); return TRUE; } static gboolean nsgtk_window_button_press_event(GtkWidget *widget, GdkEventButton *event, gpointer data) { struct gui_window *g = data; gtk_widget_grab_focus(GTK_WIDGET(g->layout)); gtk_widget_hide(GTK_WIDGET(nsgtk_scaffolding_history_window( g->scaffold)->window)); g->mouse.pressed_x = event->x / g->bw->scale; g->mouse.pressed_y = event->y / g->bw->scale; switch (event->button) { case 1: /* Left button, usually. Pass to core as BUTTON 1. */ g->mouse.state = BROWSER_MOUSE_PRESS_1; break; case 2: /* Middle button, usually. Pass to core as BUTTON 2 */ g->mouse.state = BROWSER_MOUSE_PRESS_2; break; case 3: /* Right button, usually. Action button, context menu. */ browser_window_remove_caret(g->bw); nsgtk_scaffolding_popup_menu(g->scaffold, g->mouse.pressed_x, g->mouse.pressed_y); return TRUE; default: return FALSE; } /* Handle the modifiers too */ if (event->state & GDK_SHIFT_MASK) g->mouse.state |= BROWSER_MOUSE_MOD_1; if (event->state & GDK_CONTROL_MASK) g->mouse.state |= BROWSER_MOUSE_MOD_2; /* Record where we pressed, for use when determining whether to start * a drag in motion notify events. */ g->last_x = event->x; g->last_y = event->y; browser_window_mouse_click(g->bw, g->mouse.state, g->mouse.pressed_x, g->mouse.pressed_y); return TRUE; } static gboolean nsgtk_window_button_release_event(GtkWidget *widget, GdkEventButton *event, gpointer data) { struct gui_window *g = data; bool shift = event->state & GDK_SHIFT_MASK; bool ctrl = event->state & GDK_CONTROL_MASK; /* If the mouse state is PRESS then we are waiting for a release to emit * a click event, otherwise just reset the state to nothing */ if (g->mouse.state & BROWSER_MOUSE_PRESS_1) g->mouse.state ^= (BROWSER_MOUSE_PRESS_1 | BROWSER_MOUSE_CLICK_1); else if (g->mouse.state & BROWSER_MOUSE_PRESS_2) g->mouse.state ^= (BROWSER_MOUSE_PRESS_2 | BROWSER_MOUSE_CLICK_2); /* Handle modifiers being removed */ if (g->mouse.state & BROWSER_MOUSE_MOD_1 && !shift) g->mouse.state ^= BROWSER_MOUSE_MOD_1; if (g->mouse.state & BROWSER_MOUSE_MOD_2 && !ctrl) g->mouse.state ^= BROWSER_MOUSE_MOD_2; if (g->mouse.state & (BROWSER_MOUSE_CLICK_1|BROWSER_MOUSE_CLICK_2)) { browser_window_mouse_click(g->bw, g->mouse.state, event->x / g->bw->scale, event->y / g->bw->scale); } else { browser_window_mouse_track(g->bw, 0, event->x / g->bw->scale, event->y / g->bw->scale); } g->mouse.state = 0; return TRUE; } static gboolean nsgtk_window_scroll_event(GtkWidget *widget, GdkEventScroll *event, gpointer data) { struct gui_window *g = data; double value; GtkAdjustment *vscroll = nsgtk_layout_get_vadjustment(g->layout); GtkAdjustment *hscroll = nsgtk_layout_get_hadjustment(g->layout); GtkAllocation alloc; LOG(("%d", event->direction)); switch (event->direction) { case GDK_SCROLL_LEFT: if (browser_window_scroll_at_point(g->bw, event->x / g->bw->scale, event->y / g->bw->scale, -100, 0) != true) { /* core did not handle event do horizontal scroll */ value = gtk_adjustment_get_value(hscroll) - (nsgtk_adjustment_get_step_increment(hscroll) *2); if (value < nsgtk_adjustment_get_lower(hscroll)) { value = nsgtk_adjustment_get_lower(hscroll); } gtk_adjustment_set_value(hscroll, value); } break; case GDK_SCROLL_UP: if (browser_window_scroll_at_point(g->bw, event->x / g->bw->scale, event->y / g->bw->scale, 0, -100) != true) { /* core did not handle event change vertical * adjustment. */ value = gtk_adjustment_get_value(vscroll) - (nsgtk_adjustment_get_step_increment(vscroll) * 2); if (value < nsgtk_adjustment_get_lower(vscroll)) { value = nsgtk_adjustment_get_lower(vscroll); } gtk_adjustment_set_value(vscroll, value); } break; case GDK_SCROLL_RIGHT: if (browser_window_scroll_at_point(g->bw, event->x / g->bw->scale, event->y / g->bw->scale, 100, 0) != true) { /* core did not handle event change horizontal * adjustment. */ value = gtk_adjustment_get_value(hscroll) + (nsgtk_adjustment_get_step_increment(hscroll) * 2); /* @todo consider gtk_widget_get_allocated_width() */ nsgtk_widget_get_allocation(GTK_WIDGET(g->layout), &alloc); if (value > nsgtk_adjustment_get_upper(hscroll) - alloc.width) { value = nsgtk_adjustment_get_upper(hscroll) - alloc.width; } gtk_adjustment_set_value(hscroll, value); } break; case GDK_SCROLL_DOWN: if (browser_window_scroll_at_point(g->bw, event->x / g->bw->scale, event->y / g->bw->scale, 0, 100) != true) { /* core did not handle event change vertical * adjustment. */ value = gtk_adjustment_get_value(vscroll) + (nsgtk_adjustment_get_step_increment(vscroll) * 2); /* @todo consider gtk_widget_get_allocated_height */ nsgtk_widget_get_allocation(GTK_WIDGET(g->layout), &alloc); if (value > nsgtk_adjustment_get_upper(vscroll) - alloc.height) { value = nsgtk_adjustment_get_upper(vscroll) - alloc.height; } gtk_adjustment_set_value(vscroll, value); } break; default: break; } return TRUE; } static gboolean nsgtk_window_keypress_event(GtkWidget *widget, GdkEventKey *event, gpointer data) { struct gui_window *g = data; uint32_t nskey = gtk_gui_gdkkey_to_nskey(event); if (browser_window_key_press(g->bw, nskey)) return TRUE; if ((event->state & 0x7) != 0) return TRUE; double value; GtkAdjustment *vscroll = nsgtk_layout_get_vadjustment(g->layout); GtkAdjustment *hscroll = nsgtk_layout_get_hadjustment(g->layout); GtkAllocation alloc; /* @todo consider gtk_widget_get_allocated_width() */ nsgtk_widget_get_allocation(GTK_WIDGET(g->layout), &alloc); switch (event->keyval) { case GDK_KEY(Home): case GDK_KEY(KP_Home): value = nsgtk_adjustment_get_lower(vscroll); gtk_adjustment_set_value(vscroll, value); break; case GDK_KEY(End): case GDK_KEY(KP_End): value = nsgtk_adjustment_get_upper(vscroll) - alloc.height; if (value < nsgtk_adjustment_get_lower(vscroll)) value = nsgtk_adjustment_get_lower(vscroll); gtk_adjustment_set_value(vscroll, value); break; case GDK_KEY(Left): case GDK_KEY(KP_Left): value = gtk_adjustment_get_value(hscroll) - nsgtk_adjustment_get_step_increment(hscroll); if (value < nsgtk_adjustment_get_lower(hscroll)) value = nsgtk_adjustment_get_lower(hscroll); gtk_adjustment_set_value(hscroll, value); break; case GDK_KEY(Up): case GDK_KEY(KP_Up): value = gtk_adjustment_get_value(vscroll) - nsgtk_adjustment_get_step_increment(vscroll); if (value < nsgtk_adjustment_get_lower(vscroll)) value = nsgtk_adjustment_get_lower(vscroll); gtk_adjustment_set_value(vscroll, value); break; case GDK_KEY(Right): case GDK_KEY(KP_Right): value = gtk_adjustment_get_value(hscroll) + nsgtk_adjustment_get_step_increment(hscroll); if (value > nsgtk_adjustment_get_upper(hscroll) - alloc.width) value = nsgtk_adjustment_get_upper(hscroll) - alloc.width; gtk_adjustment_set_value(hscroll, value); break; case GDK_KEY(Down): case GDK_KEY(KP_Down): value = gtk_adjustment_get_value(vscroll) + nsgtk_adjustment_get_step_increment(vscroll); if (value > nsgtk_adjustment_get_upper(vscroll) - alloc.height) value = nsgtk_adjustment_get_upper(vscroll) - alloc.height; gtk_adjustment_set_value(vscroll, value); break; case GDK_KEY(Page_Up): case GDK_KEY(KP_Page_Up): value = gtk_adjustment_get_value(vscroll) - nsgtk_adjustment_get_page_increment(vscroll); if (value < nsgtk_adjustment_get_lower(vscroll)) value = nsgtk_adjustment_get_lower(vscroll); gtk_adjustment_set_value(vscroll, value); break; case GDK_KEY(Page_Down): case GDK_KEY(KP_Page_Down): value = gtk_adjustment_get_value(vscroll) + nsgtk_adjustment_get_page_increment(vscroll); if (value > nsgtk_adjustment_get_upper(vscroll) - alloc.height) value = nsgtk_adjustment_get_upper(vscroll) - alloc.height; gtk_adjustment_set_value(vscroll, value); break; default: break; } return TRUE; } static gboolean nsgtk_window_size_allocate_event(GtkWidget *widget, GtkAllocation *allocation, gpointer data) { struct gui_window *g = data; g->bw->reformat_pending = true; browser_reformat_pending = true; if (g->paned != NULL) { /* Set status bar / scroll bar proportion according to * option_toolbar_status_width */ /* TODO: Probably want to detect when the user adjusts the * status bar width, remember that proportion for the * window, and use that here. */ gtk_paned_set_position(g->paned, (nsoption_int(toolbar_status_width) * allocation->width) / 10000); } return TRUE; } /* Core interface docuemnted in desktop/gui.h to create a gui_window */ struct gui_window *gui_create_browser_window(struct browser_window *bw, struct browser_window *clone, bool new_tab) { struct gui_window *g; /**< what we're creating to return */ g = calloc(1, sizeof(*g)); if (!g) { warn_user("NoMemory", 0); return 0; } LOG(("Creating gui window %p for browser window %p", g, bw)); g->bw = bw; g->paned = NULL; g->mouse.state = 0; g->current_pointer = GUI_POINTER_DEFAULT; if (clone != NULL) { bw->scale = clone->scale; } else { bw->scale = (float) nsoption_int(scale) / 100.0; } g->careth = 0; if (new_tab) { assert(clone != NULL); g->scaffold = clone->window->scaffold; } else { /* Now construct and attach a scaffold */ g->scaffold = nsgtk_new_scaffolding(g); } if (g->scaffold == NULL) { warn_user("NoMemory", 0); free(g); return NULL; } /* Construct our primary elements */ /* top-level document (not a frame) => create a new tab */ GError* error = NULL; GtkBuilder* xml = gtk_builder_new(); if (!gtk_builder_add_from_file(xml, glade_file_location->tabcontents, &error)) { g_warning ("Couldn't load builder file: %s", error->message); g_error_free(error); return 0; } g->layout = GTK_LAYOUT(gtk_builder_get_object(xml, "layout")); g->status_bar = GTK_LABEL(gtk_builder_get_object(xml, "status_bar")); g->paned = GTK_PANED(gtk_builder_get_object(xml, "hpaned1")); /* connect the scrollbars to the layout widget */ nsgtk_layout_set_hadjustment(g->layout, gtk_range_get_adjustment(GTK_RANGE( gtk_builder_get_object(xml, "hscrollbar")))); nsgtk_layout_set_vadjustment(g->layout, gtk_range_get_adjustment(GTK_RANGE( gtk_builder_get_object(xml, "vscrollbar")))); /* add the tab to the scaffold */ bool tempback = true; switch (temp_open_background) { case -1: tempback = !(nsoption_bool(focus_new)); break; case 0: tempback = false; break; case 1: tempback = true; break; } GtkWidget *tab_contents = GTK_WIDGET(gtk_builder_get_object(xml, "tabContents")); g_object_set_data(G_OBJECT(tab_contents), "gui_window", g); nsgtk_tab_add(g, tab_contents, tempback); g_object_unref(xml); /* Attach ourselves to the list (push_top) */ if (window_list) window_list->prev = g; g->next = window_list; g->prev = NULL; window_list = g; /* set the events we're interested in receiving from the browser's * drawing area. */ gtk_widget_add_events(GTK_WIDGET(g->layout), GDK_EXPOSURE_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_SCROLL_MASK); nsgtk_widget_set_can_focus(GTK_WIDGET(g->layout), TRUE); /* set the default background colour of the drawing area to white. */ nsgtk_widget_override_background_color(GTK_WIDGET(g->layout), GTK_STATE_NORMAL, 0, 0xffff, 0xffff, 0xffff); nsgtk_connect_draw_event(GTK_WIDGET(g->layout), G_CALLBACK(nsgtk_window_draw_event), g); #define CONNECT(obj, sig, callback, ptr) \ g_signal_connect(G_OBJECT(obj), (sig), G_CALLBACK(callback), (ptr)) CONNECT(g->layout, "motion_notify_event", nsgtk_window_motion_notify_event, g); g->signalhandler[NSGTK_WINDOW_SIGNAL_CLICK] = CONNECT(g->layout, "button_press_event", nsgtk_window_button_press_event, g); CONNECT(g->layout, "button_release_event", nsgtk_window_button_release_event, g); CONNECT(g->layout, "key_press_event", nsgtk_window_keypress_event, g); CONNECT(g->layout, "size_allocate", nsgtk_window_size_allocate_event, g); CONNECT(g->layout, "scroll_event", nsgtk_window_scroll_event, g); return g; } void nsgtk_reflow_all_windows(void) { for (struct gui_window *g = window_list; g; g = g->next) { nsgtk_tab_options_changed( nsgtk_scaffolding_notebook(g->scaffold)); g->bw->reformat_pending = true; } browser_reformat_pending = true; } /** * Process pending reformats */ void nsgtk_window_process_reformats(void) { struct gui_window *g; GtkAllocation alloc; browser_reformat_pending = false; for (g = window_list; g; g = g->next) { if (!g->bw->reformat_pending) continue; g->bw->reformat_pending = false; /* @todo consider gtk_widget_get_allocated_width() */ nsgtk_widget_get_allocation(GTK_WIDGET(g->layout), &alloc); browser_window_reformat(g->bw, false, alloc.width, alloc.height); } } void nsgtk_window_destroy_browser(struct gui_window *g) { browser_window_destroy(g->bw); } void gui_window_destroy(struct gui_window *g) { if (g->prev) g->prev->next = g->next; else window_list = g->next; if (g->next) g->next->prev = g->prev; LOG(("Destroying gui_window %p", g)); assert(g != NULL); assert(g->bw != NULL); LOG((" Scaffolding: %p", g->scaffold)); LOG((" Window name: %s", g->bw->name)); /* tab => remove tab */ gtk_widget_destroy(gtk_widget_get_parent(GTK_WIDGET(g->layout))); } /** * set favicon */ void gui_window_set_icon(struct gui_window *gw, hlcache_handle *icon) { struct bitmap *icon_bitmap = NULL; /* free any existing icon */ if (gw->icon != NULL) { g_object_unref(gw->icon); gw->icon = NULL; } if (icon != NULL) { icon_bitmap = content_get_bitmap(icon); if (icon_bitmap != NULL) { LOG(("Using %p bitmap", icon_bitmap)); gw->icon = nsgdk_pixbuf_get_from_surface(icon_bitmap->surface, 16, 16); } } if (gw->icon == NULL) { LOG(("Using default favicon")); g_object_ref(favicon_pixbuf); gw->icon = favicon_pixbuf; } nsgtk_scaffolding_set_icon(gw); } static void nsgtk_redraw_caret(struct gui_window *g) { int sx, sy; if (g->careth == 0) return; gui_window_get_scroll(g, &sx, &sy); gtk_widget_queue_draw_area(GTK_WIDGET(g->layout), g->caretx - sx, g->carety - sy, 1, g->careth + 1); }
/* called back when click in browser window */ static int fb_browser_window_click(fbtk_widget_t *widget, fbtk_callback_info *cbi) { struct gui_window *gw = cbi->context; struct browser_widget_s *bwidget = fbtk_get_userpw(widget); browser_mouse_state mouse; float scale = browser_window_get_scale(gw->bw); int x = (cbi->x + bwidget->scrollx) / scale; int y = (cbi->y + bwidget->scrolly) / scale; unsigned int time_now; static struct { enum { CLICK_SINGLE, CLICK_DOUBLE, CLICK_TRIPLE } type; unsigned int time; } last_click; if (cbi->event->type != NSFB_EVENT_KEY_DOWN && cbi->event->type != NSFB_EVENT_KEY_UP) return 0; LOG(("browser window clicked at %d,%d", cbi->x, cbi->y)); switch (cbi->event->type) { case NSFB_EVENT_KEY_DOWN: switch (cbi->event->value.keycode) { case NSFB_KEY_MOUSE_1: browser_window_mouse_click(gw->bw, BROWSER_MOUSE_PRESS_1, x, y); gui_drag.state = GUI_DRAG_PRESSED; gui_drag.button = 1; gui_drag.x = x; gui_drag.y = y; break; #if 0 case NSFB_KEY_MOUSE_3: browser_window_mouse_click(gw->bw, BROWSER_MOUSE_PRESS_2, x, y); gui_drag.state = GUI_DRAG_PRESSED; gui_drag.button = 2; gui_drag.x = x; gui_drag.y = y; break; #else case NSFB_KEY_MOUSE_2: /* scroll right */ if (browser_window_scroll_at_point(gw->bw, x, y, 100, 0) == false) widget_scroll_x(gw, 100, false); break; case NSFB_KEY_MOUSE_3: /* scroll left */ if (browser_window_scroll_at_point(gw->bw, x, y, -100, 0) == false) widget_scroll_x(gw, -100, false); break; #endif case NSFB_KEY_MOUSE_4: /* scroll up */ if (browser_window_scroll_at_point(gw->bw, x, y, 0, -100) == false) { widget_scroll_y(gw, -100, false); } break; case NSFB_KEY_MOUSE_5: /* scroll down */ if (browser_window_scroll_at_point(gw->bw, x, y, 0, 100) == false) { widget_scroll_y(gw, 100, false); } break; default: break; } break; case NSFB_EVENT_KEY_UP: mouse = 0; time_now = wallclock(); switch (cbi->event->value.keycode) { case NSFB_KEY_MOUSE_1: if (gui_drag.state == GUI_DRAG_DRAG) { /* End of a drag, rather than click */ if (gui_drag.grabbed_pointer) { /* need to ungrab pointer */ fbtk_tgrab_pointer(widget); gui_drag.grabbed_pointer = false; } gui_drag.state = GUI_DRAG_NONE; /* Tell core */ browser_window_mouse_track(gw->bw, 0, x, y); break; } /* This is a click; * clear PRESSED state and pass to core */ gui_drag.state = GUI_DRAG_NONE; mouse = BROWSER_MOUSE_CLICK_1; break; #if 0 case NSFB_KEY_MOUSE_3: if (gui_drag.state == GUI_DRAG_DRAG) { /* End of a drag, rather than click */ gui_drag.state = GUI_DRAG_NONE; if (gui_drag.grabbed_pointer) { /* need to ungrab pointer */ fbtk_tgrab_pointer(widget); gui_drag.grabbed_pointer = false; } /* Tell core */ browser_window_mouse_track(gw->bw, 0, x, y); break; } /* This is a click; * clear PRESSED state and pass to core */ gui_drag.state = GUI_DRAG_NONE; mouse = BROWSER_MOUSE_CLICK_2; break; #endif default: break; } /* Determine if it's a double or triple click, allowing * 0.5 seconds (50cs) between clicks */ if (time_now < last_click.time + 50 && cbi->event->value.keycode != NSFB_KEY_MOUSE_4 && cbi->event->value.keycode != NSFB_KEY_MOUSE_5) { if (last_click.type == CLICK_SINGLE) { /* Set double click */ mouse |= BROWSER_MOUSE_DOUBLE_CLICK; last_click.type = CLICK_DOUBLE; } else if (last_click.type == CLICK_DOUBLE) { /* Set triple click */ mouse |= BROWSER_MOUSE_TRIPLE_CLICK; last_click.type = CLICK_TRIPLE; } else { /* Set normal click */ last_click.type = CLICK_SINGLE; } } else { last_click.type = CLICK_SINGLE; } if (mouse) browser_window_mouse_click(gw->bw, mouse, x, y); last_click.time = time_now; break; default: break; } return 1; }
static gboolean nsgtk_window_draw_event(GtkWidget *widget, cairo_t *cr, gpointer data) { struct gui_window *gw = data; struct gui_window *z; struct rect clip; struct redraw_context ctx = { .interactive = true, .background_images = true, .plot = &nsgtk_plotters }; double x1; double y1; double x2; double y2; assert(gw); assert(gw->bw); for (z = window_list; z && z != gw; z = z->next) continue; assert(z); assert(GTK_WIDGET(gw->layout) == widget); current_widget = (GtkWidget *)gw->layout; current_cr = cr; GtkAdjustment *vscroll = nsgtk_layout_get_vadjustment(gw->layout); GtkAdjustment *hscroll = nsgtk_layout_get_hadjustment(gw->layout); cairo_clip_extents(cr, &x1, &y1, &x2, &y2); clip.x0 = x1; clip.y0 = y1; clip.x1 = x2; clip.y1 = y2; browser_window_redraw(gw->bw, -gtk_adjustment_get_value(hscroll), -gtk_adjustment_get_value(vscroll), &clip, &ctx); if (gw->careth != 0) { nsgtk_plot_caret(gw->caretx, gw->carety, gw->careth); } current_widget = NULL; return FALSE; } #else static gboolean nsgtk_window_draw_event(GtkWidget *widget, GdkEventExpose *event, gpointer data) { struct gui_window *gw = data; struct gui_window *z; struct rect clip; struct redraw_context ctx = { .interactive = true, .background_images = true, .plot = &nsgtk_plotters }; assert(gw); assert(gw->bw); for (z = window_list; z && z != gw; z = z->next) continue; assert(z); assert(GTK_WIDGET(gw->layout) == widget); current_widget = (GtkWidget *)gw->layout; current_cr = gdk_cairo_create(nsgtk_layout_get_bin_window(gw->layout)); clip.x0 = event->area.x; clip.y0 = event->area.y; clip.x1 = event->area.x + event->area.width; clip.y1 = event->area.y + event->area.height; browser_window_redraw(gw->bw, 0, 0, &clip, &ctx); if (gw->careth != 0) { nsgtk_plot_caret(gw->caretx, gw->carety, gw->careth); } cairo_destroy(current_cr); current_widget = NULL; return FALSE; } #endif static gboolean nsgtk_window_motion_notify_event(GtkWidget *widget, GdkEventMotion *event, gpointer data) { struct gui_window *g = data; bool shift = event->state & GDK_SHIFT_MASK; bool ctrl = event->state & GDK_CONTROL_MASK; if ((abs(event->x - g->last_x) < 5) && (abs(event->y - g->last_y) < 5)) { /* Mouse hasn't moved far enough from press coordinate for this * to be considered a drag. */ return FALSE; } else { /* This is a drag, ensure it's always treated as such, even if * we drag back over the press location */ g->last_x = INT_MIN; g->last_y = INT_MIN; } if (g->mouse.state & BROWSER_MOUSE_PRESS_1) { /* Start button 1 drag */ browser_window_mouse_click(g->bw, BROWSER_MOUSE_DRAG_1, g->mouse.pressed_x, g->mouse.pressed_y); /* Replace PRESS with HOLDING and declare drag in progress */ g->mouse.state ^= (BROWSER_MOUSE_PRESS_1 | BROWSER_MOUSE_HOLDING_1); g->mouse.state |= BROWSER_MOUSE_DRAG_ON; } else if (g->mouse.state & BROWSER_MOUSE_PRESS_2) { /* Start button 2 drag */ browser_window_mouse_click(g->bw, BROWSER_MOUSE_DRAG_2, g->mouse.pressed_x, g->mouse.pressed_y); /* Replace PRESS with HOLDING and declare drag in progress */ g->mouse.state ^= (BROWSER_MOUSE_PRESS_2 | BROWSER_MOUSE_HOLDING_2); g->mouse.state |= BROWSER_MOUSE_DRAG_ON; } /* Handle modifiers being removed */ if (g->mouse.state & BROWSER_MOUSE_MOD_1 && !shift) g->mouse.state ^= BROWSER_MOUSE_MOD_1; if (g->mouse.state & BROWSER_MOUSE_MOD_2 && !ctrl) g->mouse.state ^= BROWSER_MOUSE_MOD_2; browser_window_mouse_track(g->bw, g->mouse.state, event->x / browser_window_get_scale(g->bw), event->y / browser_window_get_scale(g->bw)); return TRUE; } static gboolean nsgtk_window_button_press_event(GtkWidget *widget, GdkEventButton *event, gpointer data) { struct gui_window *g = data; gtk_widget_grab_focus(GTK_WIDGET(g->layout)); gtk_widget_hide(GTK_WIDGET(nsgtk_scaffolding_history_window( g->scaffold)->window)); g->mouse.pressed_x = event->x / browser_window_get_scale(g->bw); g->mouse.pressed_y = event->y / browser_window_get_scale(g->bw); switch (event->button) { case 1: /* Left button, usually. Pass to core as BUTTON 1. */ g->mouse.state = BROWSER_MOUSE_PRESS_1; break; case 2: /* Middle button, usually. Pass to core as BUTTON 2 */ g->mouse.state = BROWSER_MOUSE_PRESS_2; break; case 3: /* Right button, usually. Action button, context menu. */ browser_window_remove_caret(g->bw, true); nsgtk_scaffolding_popup_menu(g->scaffold, g->mouse.pressed_x, g->mouse.pressed_y); return TRUE; default: return FALSE; } /* Modify for double & triple clicks */ if (event->type == GDK_3BUTTON_PRESS) g->mouse.state |= BROWSER_MOUSE_TRIPLE_CLICK; else if (event->type == GDK_2BUTTON_PRESS) g->mouse.state |= BROWSER_MOUSE_DOUBLE_CLICK; /* Handle the modifiers too */ if (event->state & GDK_SHIFT_MASK) g->mouse.state |= BROWSER_MOUSE_MOD_1; if (event->state & GDK_CONTROL_MASK) g->mouse.state |= BROWSER_MOUSE_MOD_2; /* Record where we pressed, for use when determining whether to start * a drag in motion notify events. */ g->last_x = event->x; g->last_y = event->y; browser_window_mouse_click(g->bw, g->mouse.state, g->mouse.pressed_x, g->mouse.pressed_y); return TRUE; } static gboolean nsgtk_window_button_release_event(GtkWidget *widget, GdkEventButton *event, gpointer data) { struct gui_window *g = data; bool shift = event->state & GDK_SHIFT_MASK; bool ctrl = event->state & GDK_CONTROL_MASK; /* If the mouse state is PRESS then we are waiting for a release to emit * a click event, otherwise just reset the state to nothing */ if (g->mouse.state & BROWSER_MOUSE_PRESS_1) g->mouse.state ^= (BROWSER_MOUSE_PRESS_1 | BROWSER_MOUSE_CLICK_1); else if (g->mouse.state & BROWSER_MOUSE_PRESS_2) g->mouse.state ^= (BROWSER_MOUSE_PRESS_2 | BROWSER_MOUSE_CLICK_2); /* Handle modifiers being removed */ if (g->mouse.state & BROWSER_MOUSE_MOD_1 && !shift) g->mouse.state ^= BROWSER_MOUSE_MOD_1; if (g->mouse.state & BROWSER_MOUSE_MOD_2 && !ctrl) g->mouse.state ^= BROWSER_MOUSE_MOD_2; if (g->mouse.state & (BROWSER_MOUSE_CLICK_1 | BROWSER_MOUSE_CLICK_2)) { browser_window_mouse_click(g->bw, g->mouse.state, event->x / browser_window_get_scale(g->bw), event->y / browser_window_get_scale(g->bw)); } else { browser_window_mouse_track(g->bw, 0, event->x / browser_window_get_scale(g->bw), event->y / browser_window_get_scale(g->bw)); } g->mouse.state = 0; return TRUE; } static gboolean nsgtk_window_scroll_event(GtkWidget *widget, GdkEventScroll *event, gpointer data) { struct gui_window *g = data; double value; double deltax = 0; double deltay = 0; GtkAdjustment *vscroll = nsgtk_layout_get_vadjustment(g->layout); GtkAdjustment *hscroll = nsgtk_layout_get_hadjustment(g->layout); GtkAllocation alloc; switch (event->direction) { case GDK_SCROLL_LEFT: deltax = -1.0; break; case GDK_SCROLL_UP: deltay = -1.0; break; case GDK_SCROLL_RIGHT: deltax = 1.0; break; case GDK_SCROLL_DOWN: deltay = 1.0; break; #if GTK_CHECK_VERSION(3,4,0) case GDK_SCROLL_SMOOTH: gdk_event_get_scroll_deltas((GdkEvent *)event, &deltax, &deltay); break; #endif default: LOG(("Unhandled mouse scroll direction")); return TRUE; } deltax *= nsgtk_adjustment_get_step_increment(hscroll); deltay *= nsgtk_adjustment_get_step_increment(vscroll); if (browser_window_scroll_at_point(g->bw, event->x / browser_window_get_scale(g->bw), event->y / browser_window_get_scale(g->bw), deltax, deltay) != true) { /* core did not handle event so change adjustments */ /* Horizontal */ if (deltax != 0) { value = gtk_adjustment_get_value(hscroll) + deltax; /* @todo consider gtk_widget_get_allocated_width() */ nsgtk_widget_get_allocation(GTK_WIDGET(g->layout), &alloc); if (value > nsgtk_adjustment_get_upper(hscroll) - alloc.width) { value = nsgtk_adjustment_get_upper(hscroll) - alloc.width; } if (value < nsgtk_adjustment_get_lower(hscroll)) { value = nsgtk_adjustment_get_lower(hscroll); } gtk_adjustment_set_value(hscroll, value); } /* Vertical */ if (deltay != 0) { value = gtk_adjustment_get_value(vscroll) + deltay; /* @todo consider gtk_widget_get_allocated_height */ nsgtk_widget_get_allocation(GTK_WIDGET(g->layout), &alloc); if (value > (nsgtk_adjustment_get_upper(vscroll) - alloc.height)) { value = nsgtk_adjustment_get_upper(vscroll) - alloc.height; } if (value < nsgtk_adjustment_get_lower(vscroll)) { value = nsgtk_adjustment_get_lower(vscroll); } gtk_adjustment_set_value(vscroll, value); } } return TRUE; } static gboolean nsgtk_window_keypress_event(GtkWidget *widget, GdkEventKey *event, gpointer data) { struct gui_window *g = data; uint32_t nskey = gtk_gui_gdkkey_to_nskey(event); if (browser_window_key_press(g->bw, nskey)) return TRUE; if ((event->state & 0x7) != 0) return TRUE; double value; GtkAdjustment *vscroll = nsgtk_layout_get_vadjustment(g->layout); GtkAdjustment *hscroll = nsgtk_layout_get_hadjustment(g->layout); GtkAllocation alloc; /* @todo consider gtk_widget_get_allocated_width() */ nsgtk_widget_get_allocation(GTK_WIDGET(g->layout), &alloc); switch (event->keyval) { case GDK_KEY(Home): case GDK_KEY(KP_Home): value = nsgtk_adjustment_get_lower(vscroll); gtk_adjustment_set_value(vscroll, value); break; case GDK_KEY(End): case GDK_KEY(KP_End): value = nsgtk_adjustment_get_upper(vscroll) - alloc.height; if (value < nsgtk_adjustment_get_lower(vscroll)) value = nsgtk_adjustment_get_lower(vscroll); gtk_adjustment_set_value(vscroll, value); break; case GDK_KEY(Left): case GDK_KEY(KP_Left): value = gtk_adjustment_get_value(hscroll) - nsgtk_adjustment_get_step_increment(hscroll); if (value < nsgtk_adjustment_get_lower(hscroll)) value = nsgtk_adjustment_get_lower(hscroll); gtk_adjustment_set_value(hscroll, value); break; case GDK_KEY(Up): case GDK_KEY(KP_Up): value = gtk_adjustment_get_value(vscroll) - nsgtk_adjustment_get_step_increment(vscroll); if (value < nsgtk_adjustment_get_lower(vscroll)) value = nsgtk_adjustment_get_lower(vscroll); gtk_adjustment_set_value(vscroll, value); break; case GDK_KEY(Right): case GDK_KEY(KP_Right): value = gtk_adjustment_get_value(hscroll) + nsgtk_adjustment_get_step_increment(hscroll); if (value > nsgtk_adjustment_get_upper(hscroll) - alloc.width) value = nsgtk_adjustment_get_upper(hscroll) - alloc.width; gtk_adjustment_set_value(hscroll, value); break; case GDK_KEY(Down): case GDK_KEY(KP_Down): value = gtk_adjustment_get_value(vscroll) + nsgtk_adjustment_get_step_increment(vscroll); if (value > nsgtk_adjustment_get_upper(vscroll) - alloc.height) value = nsgtk_adjustment_get_upper(vscroll) - alloc.height; gtk_adjustment_set_value(vscroll, value); break; case GDK_KEY(Page_Up): case GDK_KEY(KP_Page_Up): value = gtk_adjustment_get_value(vscroll) - nsgtk_adjustment_get_page_increment(vscroll); if (value < nsgtk_adjustment_get_lower(vscroll)) value = nsgtk_adjustment_get_lower(vscroll); gtk_adjustment_set_value(vscroll, value); break; case GDK_KEY(Page_Down): case GDK_KEY(KP_Page_Down): value = gtk_adjustment_get_value(vscroll) + nsgtk_adjustment_get_page_increment(vscroll); if (value > nsgtk_adjustment_get_upper(vscroll) - alloc.height) value = nsgtk_adjustment_get_upper(vscroll) - alloc.height; gtk_adjustment_set_value(vscroll, value); break; default: break; } return TRUE; } static gboolean nsgtk_window_size_allocate_event(GtkWidget *widget, GtkAllocation *allocation, gpointer data) { struct gui_window *g = data; g->bw->reformat_pending = true; browser_reformat_pending = true; return TRUE; } /** when the pane position is changed update the user option * * The slightly awkward implementation with the first allocation flag * is necessary because the initial window creation does not cause an * allocate-event signal so the position value in the pane is incorrect * and we cannot know what it should be until after the allocation * (which did not generate a signal) is done as the user position is a * percentage of pane total width not an absolute value. */ static void nsgtk_paned_notify__position(GObject *gobject, GParamSpec *pspec, gpointer data) { struct gui_window *g = data; GtkAllocation pane_alloc; gtk_widget_get_allocation(GTK_WIDGET(g->paned), &pane_alloc); if (g->paned_sized == false) { g->paned_sized = true; gtk_paned_set_position(g->paned, (nsoption_int(toolbar_status_size) * pane_alloc.width) / 10000); return; } nsoption_set_int(toolbar_status_size, ((gtk_paned_get_position(g->paned) * 10000) / (pane_alloc.width - 1))); } /** Set status bar / scroll bar proportion according to user option * when pane is resized. */ static gboolean nsgtk_paned_size_allocate_event(GtkWidget *widget, GtkAllocation *allocation, gpointer data) { gtk_paned_set_position(GTK_PANED(widget), (nsoption_int(toolbar_status_size) * allocation->width) / 10000); return TRUE; } /* destroy the browsing context as there is nothing to display it now */ static void window_destroy(GtkWidget *widget, gpointer data) { struct gui_window *gw = data; browser_window_destroy(gw->bw); } /* Core interface documented in desktop/gui.h to create a gui_window */ static struct gui_window * gui_window_create(struct browser_window *bw, struct gui_window *existing, gui_window_create_flags flags) { struct gui_window *g; /**< what we're creating to return */ GError* error = NULL; bool tempback; GtkBuilder* xml; /* open builder file first to ease error handling on faliure */ xml = gtk_builder_new(); if (!gtk_builder_add_from_file(xml, glade_file_location->tabcontents, &error)) { g_warning ("Couldn't load builder file: %s", error->message); g_error_free(error); return NULL; } g = calloc(1, sizeof(*g)); if (!g) { warn_user("NoMemory", 0); g_object_unref(xml); return NULL; } LOG(("Creating gui window %p for browser window %p", g, bw)); g->bw = bw; g->mouse.state = 0; g->current_pointer = GUI_POINTER_DEFAULT; if (flags & GW_CREATE_CLONE) { assert(existing != NULL); bw->scale = existing->bw->scale; } else { bw->scale = nsoption_int(scale) / 100; } /* attach scaffold */ if (flags & GW_CREATE_TAB) { assert(existing != NULL); g->scaffold = existing->scaffold; } else { /* Now construct and attach a scaffold */ g->scaffold = nsgtk_new_scaffolding(g); } if (g->scaffold == NULL) { warn_user("NoMemory", 0); free(g); g_object_unref(xml); return NULL; } /* Construct our primary elements */ g->container = GTK_WIDGET(gtk_builder_get_object(xml, "tabContents")); g->layout = GTK_LAYOUT(gtk_builder_get_object(xml, "layout")); g->status_bar = GTK_LABEL(gtk_builder_get_object(xml, "status_bar")); g->paned = GTK_PANED(gtk_builder_get_object(xml, "hpaned1")); /* add new gui window to global list (push_top) */ if (window_list) { window_list->prev = g; } g->next = window_list; g->prev = NULL; window_list = g; /* set the events we're interested in receiving from the browser's * drawing area. */ gtk_widget_add_events(GTK_WIDGET(g->layout), GDK_EXPOSURE_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_SCROLL_MASK); nsgtk_widget_set_can_focus(GTK_WIDGET(g->layout), TRUE); /* set the default background colour of the drawing area to white. */ nsgtk_widget_override_background_color(GTK_WIDGET(g->layout), GTK_STATE_NORMAL, 0, 0xffff, 0xffff, 0xffff); nsgtk_connect_draw_event(GTK_WIDGET(g->layout), G_CALLBACK(nsgtk_window_draw_event), g); /* layout signals */ CONNECT(g->layout, "motion-notify-event", nsgtk_window_motion_notify_event, g); g->signalhandler[NSGTK_WINDOW_SIGNAL_CLICK] = CONNECT(g->layout, "button-press-event", nsgtk_window_button_press_event, g); CONNECT(g->layout, "button-release-event", nsgtk_window_button_release_event, g); CONNECT(g->layout, "key-press-event", nsgtk_window_keypress_event, g); CONNECT(g->layout, "size-allocate", nsgtk_window_size_allocate_event, g); CONNECT(g->layout, "scroll-event", nsgtk_window_scroll_event, g); /* status pane signals */ CONNECT(g->paned, "size-allocate", nsgtk_paned_size_allocate_event, g); CONNECT(g->paned, "notify::position", nsgtk_paned_notify__position, g); /* gtk container destructor */ CONNECT(g->container, "destroy", window_destroy, g); /* add the tab container to the scaffold notebook */ switch (temp_open_background) { case -1: tempback = !(nsoption_bool(focus_new)); break; case 0: tempback = false; break; default: tempback = true; break; } nsgtk_tab_add(g, g->container, tempback); /* safe to drop the reference to the xml as the container is * referenced by the notebook now. */ g_object_unref(xml); return g; } void nsgtk_reflow_all_windows(void) { for (struct gui_window *g = window_list; g; g = g->next) { nsgtk_tab_options_changed( nsgtk_scaffolding_notebook(g->scaffold)); g->bw->reformat_pending = true; } browser_reformat_pending = true; } /** * Process pending reformats */ void nsgtk_window_process_reformats(void) { struct gui_window *g; GtkAllocation alloc; browser_reformat_pending = false; for (g = window_list; g; g = g->next) { if (!g->bw->reformat_pending) continue; g->bw->reformat_pending = false; /* @todo consider gtk_widget_get_allocated_width() */ nsgtk_widget_get_allocation(GTK_WIDGET(g->layout), &alloc); browser_window_reformat(g->bw, false, alloc.width, alloc.height); } } void nsgtk_window_destroy_browser(struct gui_window *gw) { /* remove tab */ gtk_widget_destroy(gw->container); }
static void __CDECL browser_evnt_mbutton( COMPONENT * c, long buff[8], void * data) { short mx, my, dummy, mbut; LGRECT cwork; browser_mouse_state bmstate = 0; struct gui_window * gw = data; if( input_window != gw ){ input_window = gw; } window_set_focus( gw, BROWSER, (void*)gw->browser ); browser_get_rect( gw, BR_CONTENT, &cwork ); /* convert screen coords to component coords: */ mx = evnt.mx - cwork.g_x; my = evnt.my - cwork.g_y; /* Translate GEM key state to netsurf mouse modifier */ if( evnt.mkstate & (K_RSHIFT | K_LSHIFT) ){ bmstate |= BROWSER_MOUSE_MOD_1; } else { bmstate &= ~(BROWSER_MOUSE_MOD_1); } if( (evnt.mkstate & K_CTRL) ){ bmstate |= BROWSER_MOUSE_MOD_2; } else { bmstate &= ~(BROWSER_MOUSE_MOD_2); } if( (evnt.mkstate & K_ALT) ){ bmstate |= BROWSER_MOUSE_MOD_3; } else { bmstate &= ~(BROWSER_MOUSE_MOD_3); } /* convert component coords to scrolled content coords: */ int sx_origin = (mx + gw->browser->scroll.current.x); int sy_origin = (my + gw->browser->scroll.current.y); short rel_cur_x, rel_cur_y; short prev_x=sx_origin, prev_y=sy_origin; bool dragmode = 0; /* Detect left mouse button state and compare with event state: */ graf_mkstate(&rel_cur_x, &rel_cur_y, &mbut, &dummy); if( (mbut & 1) && (evnt.mbut & 1) ){ /* Mouse still pressed, report drag */ rel_cur_x = (rel_cur_x - cwork.g_x) + gw->browser->scroll.current.x; rel_cur_y = (rel_cur_y - cwork.g_y) + gw->browser->scroll.current.y; browser_window_mouse_click( gw->browser->bw, BROWSER_MOUSE_DRAG_ON|BROWSER_MOUSE_DRAG_1, sx_origin, sy_origin); do{ if( abs(prev_x-rel_cur_x) > 5 || abs(prev_y-rel_cur_y) > 5 ){ browser_window_mouse_track( gw->browser->bw, BROWSER_MOUSE_DRAG_ON|BROWSER_MOUSE_DRAG_1, rel_cur_x, rel_cur_y); prev_x = rel_cur_x; prev_y = rel_cur_y; dragmode = true; } else { if( dragmode == false ){ browser_window_mouse_track( gw->browser->bw,BROWSER_MOUSE_PRESS_1, rel_cur_x, rel_cur_y); } } if( browser_redraw_required( gw ) ){ browser_redraw( gw ); } graf_mkstate(&rel_cur_x, &rel_cur_y, &mbut, &dummy); rel_cur_x = (rel_cur_x - cwork.g_x) + gw->browser->scroll.current.x; rel_cur_y = (rel_cur_y - cwork.g_y) + gw->browser->scroll.current.y; } while( mbut & 1 ); browser_window_mouse_track(gw->browser->bw, 0, rel_cur_x,rel_cur_y); } else { /* Right button pressed? */ if( (evnt.mbut & 2 ) ) { context_popup( gw, evnt.mx, evnt.my ); } else { browser_window_mouse_click(gw->browser->bw, bmstate|BROWSER_MOUSE_PRESS_1, sx_origin,sy_origin); browser_window_mouse_click(gw->browser->bw, bmstate|BROWSER_MOUSE_CLICK_1, sx_origin,sy_origin); } } }
/* called back when click in browser window */ static int fb_browser_window_click(fbtk_widget_t *widget, fbtk_callback_info *cbi) { struct gui_window *gw = cbi->context; struct browser_widget_s *bwidget = fbtk_get_userpw(widget); float scale = gw->bw->scale; int x = (cbi->x + bwidget->scrollx) / scale; int y = (cbi->y + bwidget->scrolly) / scale; if (cbi->event->type != NSFB_EVENT_KEY_DOWN && cbi->event->type != NSFB_EVENT_KEY_UP) return 0; LOG(("browser window clicked at %d,%d", cbi->x, cbi->y)); switch (cbi->event->type) { case NSFB_EVENT_KEY_DOWN: switch (cbi->event->value.keycode) { case NSFB_KEY_MOUSE_1: browser_window_mouse_click(gw->bw, BROWSER_MOUSE_PRESS_1, x, y); gui_drag.state = GUI_DRAG_PRESSED; gui_drag.button = 1; gui_drag.x = x; gui_drag.y = y; break; case NSFB_KEY_MOUSE_3: browser_window_mouse_click(gw->bw, BROWSER_MOUSE_PRESS_2, x, y); gui_drag.state = GUI_DRAG_PRESSED; gui_drag.button = 2; gui_drag.x = x; gui_drag.y = y; break; case NSFB_KEY_MOUSE_4: /* scroll up */ if (browser_window_scroll_at_point(gw->bw, x, y, 0, -100) == false) widget_scroll_y(gw, -100, false); break; case NSFB_KEY_MOUSE_5: /* scroll down */ if (browser_window_scroll_at_point(gw->bw, x, y, 0, 100) == false) widget_scroll_y(gw, 100, false); break; default: break; } break; case NSFB_EVENT_KEY_UP: switch (cbi->event->value.keycode) { case NSFB_KEY_MOUSE_1: if (gui_drag.state == GUI_DRAG_DRAG) { /* End of a drag, rather than click */ if (gui_drag.grabbed_pointer) { /* need to ungrab pointer */ fbtk_tgrab_pointer(widget); gui_drag.grabbed_pointer = false; } gui_drag.state = GUI_DRAG_NONE; /* Tell core */ browser_window_mouse_track(gw->bw, 0, x, y); break; } /* This is a click; * clear PRESSED state and pass to core */ gui_drag.state = GUI_DRAG_NONE; browser_window_mouse_click(gw->bw, BROWSER_MOUSE_CLICK_1, x, y); break; case NSFB_KEY_MOUSE_3: if (gui_drag.state == GUI_DRAG_DRAG) { /* End of a drag, rather than click */ gui_drag.state = GUI_DRAG_NONE; if (gui_drag.grabbed_pointer) { /* need to ungrab pointer */ fbtk_tgrab_pointer(widget); gui_drag.grabbed_pointer = false; } /* Tell core */ browser_window_mouse_track(gw->bw, 0, x, y); break; } /* This is a click; * clear PRESSED state and pass to core */ gui_drag.state = GUI_DRAG_NONE; browser_window_mouse_click(gw->bw, BROWSER_MOUSE_CLICK_2, x, y); break; default: break; } break; default: break; } return 1; }