diff options
| author | Po Lu | 2022-12-31 18:04:18 +0800 |
|---|---|---|
| committer | Po Lu | 2022-12-31 18:04:18 +0800 |
| commit | cfbc8a5dbcd362b69b37b4e6832ae4a31834364c (patch) | |
| tree | ce003d03c4ae98f4e1d02186d78e5ae6e0d36e55 /src/androidterm.c | |
| parent | 785095c416f9bae43d2947849282b814e2c7942e (diff) | |
| download | emacs-cfbc8a5dbcd362b69b37b4e6832ae4a31834364c.tar.gz emacs-cfbc8a5dbcd362b69b37b4e6832ae4a31834364c.zip | |
Bring up the Android operating system and its window system
* .dir-locals.el (c-mode): Add ANDROID_EXPORT noise macro.
* .gitignore: Add new files to ignore.
* Makefile.in: Adjust for Android.
* admin/merge-gnulib: Add new warning.
* configure.ac: Detect Android. Run cross-configuration for
Android when appropriate.
* etc/DEBUG: Document how to debug Emacs on Android.
* java/AndroidManifest.xml:
* java/Makefile.in:
* java/README:
* java/debug.sh:
* java/org/gnu/emacs/EmacsActivity.java (EmacsActivity):
* java/org/gnu/emacs/EmacsApplication.java (EmacsApplication):
* java/org/gnu/emacs/EmacsCopyArea.java (EmacsCopyArea):
* java/org/gnu/emacs/EmacsDrawLine.java (EmacsDrawLine):
* java/org/gnu/emacs/EmacsDrawPoint.java (EmacsDrawPoint):
* java/org/gnu/emacs/EmacsDrawRectangle.java
(EmacsDrawRectangle):
* java/org/gnu/emacs/EmacsDrawable.java (EmacsDrawable):
* java/org/gnu/emacs/EmacsFillPolygon.java (EmacsFillPolygon):
* java/org/gnu/emacs/EmacsFillRectangle.java
(EmacsFillRectangle):
* java/org/gnu/emacs/EmacsFontDriver.java (EmacsFontDriver):
* java/org/gnu/emacs/EmacsGC.java (EmacsGC):
* java/org/gnu/emacs/EmacsHandleObject.java (EmacsHandleObject):
* java/org/gnu/emacs/EmacsNative.java (EmacsNative):
* java/org/gnu/emacs/EmacsPaintQueue.java (EmacsPaintQueue):
* java/org/gnu/emacs/EmacsPaintReq.java (EmacsPaintReq):
* java/org/gnu/emacs/EmacsPixmap.java (EmacsPixmap):
* java/org/gnu/emacs/EmacsSdk7FontDriver.java
(EmacsSdk7FontDriver):
* java/org/gnu/emacs/EmacsService.java (class Holder<T>)
(EmacsService):
* java/org/gnu/emacs/EmacsSurfaceView.java (EmacsSurfaceView):
* java/org/gnu/emacs/EmacsThread.java (EmacsThread):
* java/org/gnu/emacs/EmacsView.java (EmacsView):
* java/org/gnu/emacs/EmacsWindow.java (EmacsWindow): New files
and classes.
* lib-src/Makefile.in (srcdir):
* lib/Makefile.in (VPATH):
(HAVE_NATIVE_COMP):
(libgnu_a_SOURCES):
(DEPFLAGS): Configure correctly for cross-compiling.
* lib/faccessat.c:
* lib/fpending.c (__fpending):
* lib/open.c:
* lib/unistd.c (_GL_UNISTD_INLINE): Temporary adjustments to
gnulib.
* lisp/frame.el (display-graphic-p):
(display-screens):
(display-pixel-height):
(display-pixel-width):
(display-mm-height):
(display-mm-width):
(display-backing-store):
(display-save-under):
(display-planes):
(display-color-cells):
(display-visual-class): Adjust for new window system `android'.
* lisp/image/wallpaper.el (x-open-connection): Add declaration.
* lisp/loadup.el (featurep): Load up files for Android.
* lisp/net/eww.el (eww-form-submit, eww-form-file)
(eww-form-checkbox, eww-form-select): Adjust faces for android.
* lisp/term/android-win.el: New file.
* src/Makefile.in: Add new targets emacs.so and android-emacs,
then adjust for cross compilation.
* src/alloc.c (cleanup_vector): Clean up Android font entities
as well.
(garbage_collect): Mark androidterm.
* src/android-emacs.c (main):
* src/android.c (ANDROID_THROW, enum android_fd_table_entry_flags)
(struct android_emacs_service, struct android_emacs_pixmap)
(struct android_graphics_point, struct android_event_container)
(struct android_event_queue, android_run_select_thread)
(android_handle_sigusr1, android_init_events, android_pending)
(android_next_event, android_write_event, android_select)
(android_run_debug_thread, android_user_full_name)
(android_get_asset_name, android_fstat, android_fstatat)
(android_file_access_p, android_hack_asset_fd, android_open)
(android_close, JNICALL, android_init_emacs_service)
(android_init_emacs_pixmap, android_init_graphics_point)
(MAX_HANDLE, struct android_handle_entry, android_alloc_id)
(android_destroy_handle, android_resolve_handle)
(android_resolve_handle2, android_change_window_attributes)
(android_create_window, android_set_window_background)
(android_destroy_window, android_init_android_rect_class)
(android_init_emacs_gc_class, android_create_gc, android_free_gc)
(android_change_gc, android_set_clip_rectangles)
(android_reparent_window, android_lookup_method)
(android_clear_window, android_map_window, android_unmap_window)
(android_resize_window, android_move_window, android_swap_buffers)
(android_get_gc_values, android_set_foreground)
(android_fill_rectangle, android_create_pixmap_from_bitmap_data)
(android_set_clip_mask, android_set_fill_style, android_copy_area)
(android_free_pixmap, android_set_background, android_fill_polygon)
(android_draw_rectangle, android_draw_point, android_draw_line)
(android_create_pixmap, android_set_ts_origin, android_clear_area):
* src/android.h (ANDROID_EXPORT):
* src/androidfns.c (android_display_info_for_name)
(check_android_display_info, check_x_display_info, gamma_correct)
(android_defined_color, android_decode_color)
(android_implicitly_set_name, android_explicitly_set_name)
(android_set_tool_bar_lines, android_change_tool_bar_height)
(android_set_tab_bar_lines, android_change_tab_bar_height)
(android_set_scroll_bar_default_height)
(android_set_scroll_bar_default_width, android_icon_verify)
(android_icon, android_make_gc, android_free_gcs)
(unwind_create_frame, do_unwind_create_frame)
(android_default_font_parameter, android_create_frame_window)
(Fx_create_frame, Fxw_color_defined_p, Fxw_color_values)
(Fxw_display_color_p, Fx_display_grayscale_p)
(Fx_display_pixel_width, Fx_display_pixel_height)
(Fx_display_planes, Fx_display_color_cells, Fx_display_screens)
(Fx_display_mm_width, Fx_display_mm_height)
(Fx_display_backing_store, Fx_display_visual_class)
(Fx_display_monitor_attributes_list, Fx_frame_geometry)
(Fx_frame_list_z_order, Fx_frame_restack)
(Fx_mouse_absolute_pixel_position)
(Fx_set_mouse_absolute_pixel_position, Fandroid_get_connection)
(Fx_display_list, Fx_show_tip, Fx_hide_tip)
(android_set_background_color, android_set_border_color)
(android_set_cursor_color, android_set_cursor_type)
(android_set_foreground_color)
(android_set_child_frame_border_width)
(android_set_internal_border_width, android_set_menu_bar_lines)
(android_set_mouse_color, android_set_title, android_set_alpha)
(android_frame_parm_handlers, syms_of_androidfns):
* src/androidfont.c (struct android_emacs_font_driver)
(struct android_emacs_font_spec, struct android_emacs_font_metrics)
(struct android_emacs_font_object, struct android_integer)
(struct androidfont_info, struct androidfont_entity)
(android_init_font_driver, android_init_font_spec)
(android_init_font_metrics, android_init_integer)
(android_init_font_object, androidfont_get_cache)
(androidfont_from_lisp, androidfont_from_java, androidfont_list)
(androidfont_match, androidfont_draw, androidfont_open_font)
(androidfont_close_font, androidfont_has_char)
(androidfont_encode_char, androidfont_text_extents)
(androidfont_list_family, androidfont_driver)
(syms_of_androidfont_for_pdumper, syms_of_androidfont)
(init_androidfont, android_finalize_font_entity):
* src/androidgui.h (_ANDROID_GUI_H_, struct android_rectangle)
(struct android_point, enum android_gc_function)
(enum android_gc_value_mask, enum android_fill_style)
(enum android_window_value_mask)
(struct android_set_window_attributes, struct android_gc_values)
(struct android_gc, enum android_swap_action, enum android_shape)
(enum android_coord_mode, struct android_swap_info)
(NativeRectangle, struct android_any_event)
(struct android_key_event, struct android_configure_event)
(union android_event):
* src/androidterm.c (android_window_to_frame, android_clear_frame)
(android_ring_bell, android_toggle_invisible_pointer)
(android_update_begin, android_update_end, show_back_buffer)
(android_flush_dirty_back_buffer_on, handle_one_android_event)
(android_read_socket, android_frame_up_to_date)
(android_buffer_flipping_unblocked_hook)
(android_query_frame_background_color, android_parse_color)
(android_alloc_nearest_color, android_query_colors)
(android_mouse_position, android_get_focus_frame)
(android_focus_frame, android_frame_rehighlight)
(android_frame_raise_lower, android_make_frame_visible)
(android_make_frame_invisible)
(android_make_frame_visible_invisible, android_fullscreen_hook)
(android_iconify_frame, android_set_window_size_1)
(android_set_window_size, android_set_offset, android_set_alpha)
(android_new_font, android_bitmap_icon, android_free_pixmap_hook)
(android_free_frame_resources, android_delete_frame)
(android_delete_terminal, android_scroll_run)
(android_after_update_window_line, android_flip_and_flush)
(android_clear_rectangle, android_reset_clip_rectangles)
(android_clip_to_row, android_draw_fringe_bitmap)
(android_set_cursor_gc, android_set_mouse_face_gc)
(android_set_mode_line_face_gc, android_set_glyph_string_gc)
(android_set_glyph_string_clipping)
(android_set_glyph_string_clipping_exactly)
(android_compute_glyph_string_overhangs)
(android_clear_glyph_string_rect)
(android_draw_glyph_string_background, android_fill_triangle)
(android_make_point, android_inside_rect_p, android_clear_point)
(android_draw_relief_rect, android_draw_box_rect)
(HIGHLIGHT_COLOR_DARK_BOOST_LIMIT, android_setup_relief_color)
(android_setup_relief_colors, android_draw_glyph_string_box)
(android_draw_glyph_string_bg_rect, android_draw_image_relief)
(android_draw_image_foreground, android_draw_image_foreground_1)
(android_draw_image_glyph_string)
(android_draw_stretch_glyph_string, android_draw_underwave)
(android_draw_glyph_string_foreground)
(android_draw_composite_glyph_string_foreground)
(android_draw_glyphless_glyph_string_foreground)
(android_draw_glyph_string, android_define_frame_cursor)
(android_clear_frame_area, android_clear_under_internal_border)
(android_draw_hollow_cursor, android_draw_bar_cursor)
(android_draw_window_cursor, android_draw_vertical_window_border)
(android_draw_window_divider, android_redisplay_interface)
(frame_set_mouse_pixel_position, get_keysym_name)
(android_create_terminal, android_term_init, syms_of_androidterm)
(mark_androidterm):
* src/androidterm.h (_ANDROID_TERM_H_, struct android_display_info)
(struct android_output, FRAME_ANDROID_OUTPUT, XSCROLL_BAR): New
files.
* src/dired.c (file_attributes): Do not use openat on Android.
* src/dispextern.h (No_Cursor): Define appropriately on Android.
(struct glyph_string, struct face): Make gc field of type struct
android_gc on Android.
* src/dispnew.c (clear_current_matrices, clear_desired_matrices)
(adjust_frame_glyphs_for_window_redisplay, free_glyphs)
(update_frame, scrolling, char_ins_del_cost, update_frame_line)
(init_display_interactive): Disable text terminal support
completely on Android. Fix non-toolkit menus for non-X systems.
* src/editfns.c (Fuser_full_name): Call android_user_full_name.
* src/emacs.c (android_emacs_init): Make main this on Android.
Prohibit argv sorting from exceeding end of argv.
* src/epaths.in: Add path definitions for Android.
* src/fileio.c (file_access_p): Call android_file_access_p.
(file_name_directory): Avoid using openat on Android.
(Fcopy_file): Adjust to call sys_fstat instead.
(file_directory_p):
(Finsert_file_contents):
(write_region): Likewise.
* src/filelock.c:
* src/fns.c (Flocale_info): Pacify warning on Android.
* src/font.c (font_make_entity_android): New function.
* src/font.h:
* src/frame.c (Fframep):
(Fwindow_system): Handle new window system `android'. Update doc strings.
(Fmake_terminal_frame): Disable on Android.
(gui_display_get_resource): Disable get_string_resource_hook on Android.
(syms_of_frame): New defsym `android'.
* src/frame.h (GCALIGNED_STRUCT): Add new output data for
Android.
(ENUM_BF): Expand enumerator size.
(FRAME_ANDROID_P, FRAME_WINDOW_P, MOUSE_HL_INFO): Add
definitions for Android.
* src/image.c (GET_PIXEL):
(image_create_bitmap_from_file):
(image_create_x_image_and_pixmap_1):
(image_get_x_image):
(slurp_file):
(lookup_rgb_color):
(image_to_emacs_colors):
(image_from_emacs_colors):
(image_pixmap_draw_cross):
(image_disable_image):
(MaskForeground):
(gif_load): Add stubs for Android.
* src/lisp.h:
* src/lread.c (safe_to_load_version, maybe_swap_for_eln1, openp):
* src/pdumper.c (pdumper_load): Call sys_fstat instead of fstat.
* src/process.c (wait_reading_process_output): Use
android_select instead of pselect.
* src/scroll.c: Disable on Android.
* src/sysdep.c (widen_foreground_group, reset_sys_modes)
(init_signals, emacs_fstatat, sys_fstat): New function.
(emacs_open, emacs_open_noquit, emacs_close): Implement
differently on Android.
(close_output_streams): Disable what is not required on Android.
* src/term.c (OUTPUT1_IF, encode_terminal_code, string_cost)
(string_cost_one_line, per_line_cost, calculate_costs)
(struct fkey_table, tty_append_glyph, produce_glyphs)
(tty_capable_p, Fsuspend_tty, Fresume_tty, device, init_tty)
(maybe_fatal, syms_of_term): Disable text terminal support on
Android.
* src/termhooks.h (enum output_method): Add android output
method.
(GCALIGNED_STRUCT, TERMINAL_FONT_CACHE): Define for Android.
* src/terminal.c (Fterminal_live_p): Implement for Android.
* src/verbose.mk.in (AM_V_GLOBALS): Add JAVAC and DX.
* src/xdisp.c (redisplay_internal): Disable text terminals on Android.
(display_menu_bar):
(display_tty_menu_item):
(draw_row_with_mouse_face):
(expose_frame): Make the non toolkit menu bar work on Android.
* src/xfaces.c (GCGraphicsExposures):
(x_create_gc):
(x_free_gc):
(Fx_load_color_file): Define for Android.
* xcompile/Makefile.in (top_srcdir):
(top_builddir):
* xcompile/README:
* xcompile/langinfo.h (nl_langinfo): New files.
Diffstat (limited to 'src/androidterm.c')
| -rw-r--r-- | src/androidterm.c | 3161 |
1 files changed, 3161 insertions, 0 deletions
diff --git a/src/androidterm.c b/src/androidterm.c new file mode 100644 index 00000000000..bb3c2a29737 --- /dev/null +++ b/src/androidterm.c | |||
| @@ -0,0 +1,3161 @@ | |||
| 1 | /* Communication module for Android terminals. | ||
| 2 | |||
| 3 | Copyright (C) 2023 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This file is part of GNU Emacs. | ||
| 6 | |||
| 7 | GNU Emacs is free software: you can redistribute it and/or modify | ||
| 8 | it under the terms of the GNU General Public License as published by | ||
| 9 | the Free Software Foundation, either version 3 of the License, or (at | ||
| 10 | your option) any later version. | ||
| 11 | |||
| 12 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | GNU General Public License for more details. | ||
| 16 | |||
| 17 | You should have received a copy of the GNU General Public License | ||
| 18 | along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | ||
| 19 | |||
| 20 | #include <config.h> | ||
| 21 | #include <stdio.h> | ||
| 22 | |||
| 23 | #include "lisp.h" | ||
| 24 | #include "androidterm.h" | ||
| 25 | #include "keyboard.h" | ||
| 26 | #include "blockinput.h" | ||
| 27 | #include "android.h" | ||
| 28 | #include "buffer.h" | ||
| 29 | #include "window.h" | ||
| 30 | |||
| 31 | /* This is a chain of structures for all the X displays currently in | ||
| 32 | use. */ | ||
| 33 | |||
| 34 | struct android_display_info *x_display_list; | ||
| 35 | |||
| 36 | |||
| 37 | |||
| 38 | /* Android terminal interface functions. */ | ||
| 39 | |||
| 40 | #ifndef ANDROID_STUBIFY | ||
| 41 | |||
| 42 | enum | ||
| 43 | { | ||
| 44 | ANDROID_EVENT_NORMAL, | ||
| 45 | ANDROID_EVENT_GOTO_OUT, | ||
| 46 | ANDROID_EVENT_DROP, | ||
| 47 | }; | ||
| 48 | |||
| 49 | static struct frame * | ||
| 50 | android_window_to_frame (struct android_display_info *dpyinfo, | ||
| 51 | android_window wdesc) | ||
| 52 | { | ||
| 53 | Lisp_Object tail, frame; | ||
| 54 | struct frame *f; | ||
| 55 | |||
| 56 | if (wdesc == ANDROID_NONE) | ||
| 57 | return NULL; | ||
| 58 | |||
| 59 | FOR_EACH_FRAME (tail, frame) | ||
| 60 | { | ||
| 61 | f = XFRAME (frame); | ||
| 62 | |||
| 63 | if (!FRAME_ANDROID_P (f) || FRAME_DISPLAY_INFO (f) != dpyinfo) | ||
| 64 | continue; | ||
| 65 | |||
| 66 | if (FRAME_ANDROID_WINDOW (f) == wdesc) | ||
| 67 | return f; | ||
| 68 | } | ||
| 69 | |||
| 70 | return NULL; | ||
| 71 | } | ||
| 72 | |||
| 73 | static void | ||
| 74 | android_clear_frame (struct frame *f) | ||
| 75 | { | ||
| 76 | /* Clearing the frame will erase any cursor, so mark them all as no | ||
| 77 | longer visible. */ | ||
| 78 | mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f))); | ||
| 79 | android_clear_window (FRAME_ANDROID_WINDOW (f)); | ||
| 80 | } | ||
| 81 | |||
| 82 | static void | ||
| 83 | android_ring_bell (struct frame *f) | ||
| 84 | { | ||
| 85 | /* TODO */ | ||
| 86 | } | ||
| 87 | |||
| 88 | static void | ||
| 89 | android_toggle_invisible_pointer (struct frame *f, bool invisible) | ||
| 90 | { | ||
| 91 | /* TODO */ | ||
| 92 | } | ||
| 93 | |||
| 94 | /* Start an update of frame F. This function is installed as a hook | ||
| 95 | for update_begin, i.e. it is called when update_begin is called. | ||
| 96 | This function is called prior to calls to gui_update_window_begin | ||
| 97 | for each window being updated. Currently, there is nothing to do | ||
| 98 | here because all interesting stuff is done on a window basis. */ | ||
| 99 | |||
| 100 | static void | ||
| 101 | android_update_begin (struct frame *f) | ||
| 102 | { | ||
| 103 | /* The frame is no longer complete, as it is in the midst of an | ||
| 104 | update. */ | ||
| 105 | FRAME_ANDROID_COMPLETE_P (f) = false; | ||
| 106 | } | ||
| 107 | |||
| 108 | /* End update of frame F. This function is installed as a hook in | ||
| 109 | update_end. */ | ||
| 110 | |||
| 111 | static void | ||
| 112 | android_update_end (struct frame *f) | ||
| 113 | { | ||
| 114 | /* Mouse highlight may be displayed again. */ | ||
| 115 | MOUSE_HL_INFO (f)->mouse_face_defer = false; | ||
| 116 | } | ||
| 117 | |||
| 118 | static void | ||
| 119 | show_back_buffer (struct frame *f) | ||
| 120 | { | ||
| 121 | struct android_swap_info swap_info; | ||
| 122 | |||
| 123 | memset (&swap_info, 0, sizeof (swap_info)); | ||
| 124 | swap_info.swap_window = FRAME_ANDROID_WINDOW (f); | ||
| 125 | swap_info.swap_action = ANDROID_COPIED; | ||
| 126 | android_swap_buffers (&swap_info, 1); | ||
| 127 | } | ||
| 128 | |||
| 129 | /* Flip back buffers on F if it has undrawn content. */ | ||
| 130 | |||
| 131 | static void | ||
| 132 | android_flush_dirty_back_buffer_on (struct frame *f) | ||
| 133 | { | ||
| 134 | if (FRAME_GARBAGED_P (f) | ||
| 135 | || buffer_flipping_blocked_p () | ||
| 136 | /* If the frame is not already up to date, do not flush buffers | ||
| 137 | on input, as that will result in flicker. */ | ||
| 138 | || !FRAME_ANDROID_COMPLETE_P (f)) | ||
| 139 | return; | ||
| 140 | |||
| 141 | show_back_buffer (f); | ||
| 142 | } | ||
| 143 | |||
| 144 | static int | ||
| 145 | handle_one_android_event (struct android_display_info *dpyinfo, | ||
| 146 | union android_event *event, int *finish, | ||
| 147 | struct input_event *hold_quit) | ||
| 148 | { | ||
| 149 | union android_event configureEvent; | ||
| 150 | struct frame *f, *any, *mouse_frame; | ||
| 151 | Mouse_HLInfo *hlinfo; | ||
| 152 | |||
| 153 | hlinfo = &dpyinfo->mouse_highlight; | ||
| 154 | *finish = ANDROID_EVENT_NORMAL; | ||
| 155 | any = android_window_to_frame (dpyinfo, event->xany.window); | ||
| 156 | |||
| 157 | switch (event->type) | ||
| 158 | { | ||
| 159 | case ANDROID_CONFIGURE_NOTIFY: | ||
| 160 | configureEvent = *event; | ||
| 161 | |||
| 162 | f = android_window_to_frame (dpyinfo, | ||
| 163 | configureEvent.xconfigure.window); | ||
| 164 | |||
| 165 | int width = configureEvent.xconfigure.width; | ||
| 166 | int height = configureEvent.xconfigure.height; | ||
| 167 | |||
| 168 | if (CONSP (frame_size_history)) | ||
| 169 | frame_size_history_extra (f, build_string ("ConfigureNotify"), | ||
| 170 | FRAME_PIXEL_WIDTH (f), | ||
| 171 | FRAME_PIXEL_HEIGHT (f), | ||
| 172 | width, height, f->new_width, | ||
| 173 | f->new_height); | ||
| 174 | |||
| 175 | /* Even if the number of character rows and columns has | ||
| 176 | not changed, the font size may have changed, so we need | ||
| 177 | to check the pixel dimensions as well. */ | ||
| 178 | |||
| 179 | if (width != FRAME_PIXEL_WIDTH (f) | ||
| 180 | || height != FRAME_PIXEL_HEIGHT (f) | ||
| 181 | || (f->new_size_p | ||
| 182 | && ((f->new_width >= 0 && width != f->new_width) | ||
| 183 | || (f->new_height >= 0 && height != f->new_height)))) | ||
| 184 | { | ||
| 185 | change_frame_size (f, width, height, false, true, false); | ||
| 186 | android_clear_under_internal_border (f); | ||
| 187 | SET_FRAME_GARBAGED (f); | ||
| 188 | cancel_mouse_face (f); | ||
| 189 | } | ||
| 190 | |||
| 191 | goto OTHER; | ||
| 192 | |||
| 193 | case ANDROID_KEY_PRESS: | ||
| 194 | |||
| 195 | /* If mouse-highlight is an integer, input clears out | ||
| 196 | mouse highlighting. */ | ||
| 197 | if (!hlinfo->mouse_face_hidden && FIXNUMP (Vmouse_highlight) | ||
| 198 | && (any == 0 | ||
| 199 | || !EQ (f->tool_bar_window, hlinfo->mouse_face_window) | ||
| 200 | || !EQ (f->tab_bar_window, hlinfo->mouse_face_window))) | ||
| 201 | { | ||
| 202 | mouse_frame = hlinfo->mouse_face_mouse_frame; | ||
| 203 | |||
| 204 | clear_mouse_face (hlinfo); | ||
| 205 | hlinfo->mouse_face_hidden = true; | ||
| 206 | |||
| 207 | if (mouse_frame) | ||
| 208 | android_flush_dirty_back_buffer_on (mouse_frame); | ||
| 209 | } | ||
| 210 | |||
| 211 | default: | ||
| 212 | goto OTHER; | ||
| 213 | } | ||
| 214 | |||
| 215 | OTHER: | ||
| 216 | |||
| 217 | return 0; | ||
| 218 | } | ||
| 219 | |||
| 220 | static int | ||
| 221 | android_read_socket (struct terminal *terminal, | ||
| 222 | struct input_event *hold_quit) | ||
| 223 | { | ||
| 224 | int count = 0; | ||
| 225 | struct android_display_info *dpyinfo; | ||
| 226 | |||
| 227 | dpyinfo = terminal->display_info.android; | ||
| 228 | |||
| 229 | block_input (); | ||
| 230 | while (android_pending ()) | ||
| 231 | { | ||
| 232 | int finish; | ||
| 233 | union android_event event; | ||
| 234 | |||
| 235 | android_next_event (&event); | ||
| 236 | count += handle_one_android_event (dpyinfo, &event, &finish, | ||
| 237 | hold_quit); | ||
| 238 | |||
| 239 | if (finish == ANDROID_EVENT_GOTO_OUT) | ||
| 240 | break; | ||
| 241 | } | ||
| 242 | unblock_input (); | ||
| 243 | |||
| 244 | /* If the focus was just given to an auto-raising frame, raise it | ||
| 245 | now. */ | ||
| 246 | if (dpyinfo->pending_autoraise_frame) | ||
| 247 | { | ||
| 248 | /* android_raise_frame (dpyinfo->pending_autoraise_frame); | ||
| 249 | TODO */ | ||
| 250 | dpyinfo->pending_autoraise_frame = NULL; | ||
| 251 | } | ||
| 252 | |||
| 253 | return count; | ||
| 254 | } | ||
| 255 | |||
| 256 | static void | ||
| 257 | android_frame_up_to_date (struct frame *f) | ||
| 258 | { | ||
| 259 | eassert (FRAME_ANDROID_P (f)); | ||
| 260 | block_input (); | ||
| 261 | FRAME_MOUSE_UPDATE (f); | ||
| 262 | |||
| 263 | if (!buffer_flipping_blocked_p ()) | ||
| 264 | show_back_buffer (f); | ||
| 265 | |||
| 266 | /* The frame is now complete, as its contents have been drawn. */ | ||
| 267 | FRAME_ANDROID_COMPLETE_P (f) = true; | ||
| 268 | unblock_input (); | ||
| 269 | } | ||
| 270 | |||
| 271 | static void | ||
| 272 | android_buffer_flipping_unblocked_hook (struct frame *f) | ||
| 273 | { | ||
| 274 | block_input (); | ||
| 275 | show_back_buffer (f); | ||
| 276 | unblock_input (); | ||
| 277 | } | ||
| 278 | |||
| 279 | static void | ||
| 280 | android_query_frame_background_color (struct frame *f, Emacs_Color *bgcolor) | ||
| 281 | { | ||
| 282 | unsigned long background; | ||
| 283 | |||
| 284 | background = FRAME_BACKGROUND_PIXEL (f); | ||
| 285 | bgcolor->pixel = background; | ||
| 286 | |||
| 287 | android_query_colors (f, bgcolor, 1); | ||
| 288 | } | ||
| 289 | |||
| 290 | int | ||
| 291 | android_parse_color (struct frame *f, const char *color_name, | ||
| 292 | Emacs_Color *color) | ||
| 293 | { | ||
| 294 | unsigned short r, g, b; | ||
| 295 | Lisp_Object tem, tem1; | ||
| 296 | unsigned long lisp_color; | ||
| 297 | |||
| 298 | if (parse_color_spec (color_name, &r, &g, &b)) | ||
| 299 | { | ||
| 300 | color->red = r; | ||
| 301 | color->green = g; | ||
| 302 | color->blue = b; | ||
| 303 | |||
| 304 | return 1; | ||
| 305 | } | ||
| 306 | |||
| 307 | tem = x_display_list->color_map; | ||
| 308 | for (; CONSP (tem); tem = XCDR (tem)) | ||
| 309 | { | ||
| 310 | tem1 = XCAR (tem); | ||
| 311 | |||
| 312 | if (CONSP (tem1) | ||
| 313 | && !xstrcasecmp (SSDATA (XCAR (tem1)), color_name)) | ||
| 314 | { | ||
| 315 | lisp_color = XFIXNUM (XCDR (tem1)); | ||
| 316 | color->red = RED_FROM_ULONG (lisp_color) * 257; | ||
| 317 | color->green = GREEN_FROM_ULONG (lisp_color) * 257; | ||
| 318 | color->blue = BLUE_FROM_ULONG (lisp_color) * 257; | ||
| 319 | return 1; | ||
| 320 | } | ||
| 321 | } | ||
| 322 | |||
| 323 | return 0; | ||
| 324 | } | ||
| 325 | |||
| 326 | bool | ||
| 327 | android_alloc_nearest_color (struct frame *f, Emacs_Color *color) | ||
| 328 | { | ||
| 329 | gamma_correct (f, color); | ||
| 330 | color->pixel = RGB_TO_ULONG (color->red / 256, | ||
| 331 | color->green / 256, | ||
| 332 | color->blue / 256); | ||
| 333 | |||
| 334 | return true; | ||
| 335 | } | ||
| 336 | |||
| 337 | void | ||
| 338 | android_query_colors (struct frame *f, Emacs_Color *colors, int ncolors) | ||
| 339 | { | ||
| 340 | int i; | ||
| 341 | |||
| 342 | for (i = 0; i < ncolors; ++i) | ||
| 343 | { | ||
| 344 | colors[i].red = RED_FROM_ULONG (colors[i].pixel) * 257; | ||
| 345 | colors[i].green = RED_FROM_ULONG (colors[i].pixel) * 257; | ||
| 346 | colors[i].blue = RED_FROM_ULONG (colors[i].pixel) * 257; | ||
| 347 | } | ||
| 348 | } | ||
| 349 | |||
| 350 | static void | ||
| 351 | android_mouse_position (struct frame **fp, int insist, | ||
| 352 | Lisp_Object *bar_window, | ||
| 353 | enum scroll_bar_part *part, Lisp_Object *x, | ||
| 354 | Lisp_Object *y, Time *timestamp) | ||
| 355 | { | ||
| 356 | /* TODO */ | ||
| 357 | } | ||
| 358 | |||
| 359 | static Lisp_Object | ||
| 360 | android_get_focus_frame (struct frame *f) | ||
| 361 | { | ||
| 362 | Lisp_Object lisp_focus; | ||
| 363 | struct frame *focus; | ||
| 364 | |||
| 365 | focus = FRAME_DISPLAY_INFO (f)->focus_frame; | ||
| 366 | |||
| 367 | if (!focus) | ||
| 368 | return Qnil; | ||
| 369 | |||
| 370 | XSETFRAME (lisp_focus, focus); | ||
| 371 | return lisp_focus; | ||
| 372 | } | ||
| 373 | |||
| 374 | static void | ||
| 375 | android_focus_frame (struct frame *f, bool noactivate) | ||
| 376 | { | ||
| 377 | /* TODO */ | ||
| 378 | } | ||
| 379 | |||
| 380 | static void | ||
| 381 | android_frame_rehighlight (struct frame *f) | ||
| 382 | { | ||
| 383 | /* TODO */ | ||
| 384 | } | ||
| 385 | |||
| 386 | static void | ||
| 387 | android_frame_raise_lower (struct frame *f, bool raise_flag) | ||
| 388 | { | ||
| 389 | /* TODO */ | ||
| 390 | } | ||
| 391 | |||
| 392 | void | ||
| 393 | android_make_frame_visible (struct frame *f) | ||
| 394 | { | ||
| 395 | android_map_window (FRAME_ANDROID_WINDOW (f)); | ||
| 396 | |||
| 397 | SET_FRAME_VISIBLE (f, true); | ||
| 398 | SET_FRAME_ICONIFIED (f, false); | ||
| 399 | } | ||
| 400 | |||
| 401 | void | ||
| 402 | android_make_frame_invisible (struct frame *f) | ||
| 403 | { | ||
| 404 | android_unmap_window (FRAME_ANDROID_WINDOW (f)); | ||
| 405 | |||
| 406 | SET_FRAME_VISIBLE (f, false); | ||
| 407 | SET_FRAME_ICONIFIED (f, false); | ||
| 408 | } | ||
| 409 | |||
| 410 | static void | ||
| 411 | android_make_frame_visible_invisible (struct frame *f, bool visible) | ||
| 412 | { | ||
| 413 | if (visible) | ||
| 414 | android_make_frame_visible (f); | ||
| 415 | else | ||
| 416 | android_make_frame_invisible (f); | ||
| 417 | } | ||
| 418 | |||
| 419 | static void | ||
| 420 | android_fullscreen_hook (struct frame *f) | ||
| 421 | { | ||
| 422 | /* TODO */ | ||
| 423 | } | ||
| 424 | |||
| 425 | void | ||
| 426 | android_iconify_frame (struct frame *f) | ||
| 427 | { | ||
| 428 | /* TODO */ | ||
| 429 | } | ||
| 430 | |||
| 431 | static void | ||
| 432 | android_set_window_size_1 (struct frame *f, bool change_gravity, | ||
| 433 | int width, int height) | ||
| 434 | { | ||
| 435 | if (change_gravity) | ||
| 436 | f->win_gravity = NorthWestGravity; | ||
| 437 | |||
| 438 | android_resize_window (FRAME_ANDROID_WINDOW (f), width, | ||
| 439 | height); | ||
| 440 | |||
| 441 | /* We've set {FRAME,PIXEL}_{WIDTH,HEIGHT} to the values we hope to | ||
| 442 | receive in the ConfigureNotify event; if we get what we asked | ||
| 443 | for, then the event won't cause the screen to become garbaged, so | ||
| 444 | we have to make sure to do it here. */ | ||
| 445 | SET_FRAME_GARBAGED (f); | ||
| 446 | } | ||
| 447 | |||
| 448 | void | ||
| 449 | android_set_window_size (struct frame *f, bool change_gravity, | ||
| 450 | int width, int height) | ||
| 451 | { | ||
| 452 | block_input (); | ||
| 453 | |||
| 454 | android_set_window_size_1 (f, change_gravity, width, height); | ||
| 455 | android_clear_under_internal_border (f); | ||
| 456 | |||
| 457 | /* If cursor was outside the new size, mark it as off. */ | ||
| 458 | mark_window_cursors_off (XWINDOW (f->root_window)); | ||
| 459 | |||
| 460 | /* Clear out any recollection of where the mouse highlighting was, | ||
| 461 | since it might be in a place that's outside the new frame size. | ||
| 462 | Actually checking whether it is outside is a pain in the neck, | ||
| 463 | so don't try--just let the highlighting be done afresh with new size. */ | ||
| 464 | cancel_mouse_face (f); | ||
| 465 | |||
| 466 | unblock_input (); | ||
| 467 | |||
| 468 | do_pending_window_change (false); | ||
| 469 | } | ||
| 470 | |||
| 471 | static void | ||
| 472 | android_set_offset (struct frame *f, int xoff, int yoff, | ||
| 473 | int change_gravity) | ||
| 474 | { | ||
| 475 | if (change_gravity > 0) | ||
| 476 | { | ||
| 477 | f->top_pos = yoff; | ||
| 478 | f->left_pos = xoff; | ||
| 479 | f->size_hint_flags &= ~ (XNegative | YNegative); | ||
| 480 | if (xoff < 0) | ||
| 481 | f->size_hint_flags |= XNegative; | ||
| 482 | if (yoff < 0) | ||
| 483 | f->size_hint_flags |= YNegative; | ||
| 484 | f->win_gravity = NorthWestGravity; | ||
| 485 | } | ||
| 486 | |||
| 487 | android_move_window (FRAME_ANDROID_WINDOW (f), xoff, yoff); | ||
| 488 | } | ||
| 489 | |||
| 490 | static void | ||
| 491 | android_set_alpha (struct frame *f) | ||
| 492 | { | ||
| 493 | /* TODO */ | ||
| 494 | } | ||
| 495 | |||
| 496 | static Lisp_Object | ||
| 497 | android_new_font (struct frame *f, Lisp_Object font_object, int fontset) | ||
| 498 | { | ||
| 499 | struct font *font = XFONT_OBJECT (font_object); | ||
| 500 | int unit, font_ascent, font_descent; | ||
| 501 | |||
| 502 | if (fontset < 0) | ||
| 503 | fontset = fontset_from_font (font_object); | ||
| 504 | FRAME_FONTSET (f) = fontset; | ||
| 505 | if (FRAME_FONT (f) == font) | ||
| 506 | /* This font is already set in frame F. There's nothing more to | ||
| 507 | do. */ | ||
| 508 | return font_object; | ||
| 509 | |||
| 510 | FRAME_FONT (f) = font; | ||
| 511 | FRAME_BASELINE_OFFSET (f) = font->baseline_offset; | ||
| 512 | FRAME_COLUMN_WIDTH (f) = font->average_width; | ||
| 513 | get_font_ascent_descent (font, &font_ascent, &font_descent); | ||
| 514 | FRAME_LINE_HEIGHT (f) = font_ascent + font_descent; | ||
| 515 | |||
| 516 | /* We could use a more elaborate calculation here. */ | ||
| 517 | FRAME_TAB_BAR_HEIGHT (f) = FRAME_TAB_BAR_LINES (f) * FRAME_LINE_HEIGHT (f); | ||
| 518 | |||
| 519 | /* Compute character columns occupied by scrollbar. | ||
| 520 | |||
| 521 | Don't do things differently for non-toolkit scrollbars | ||
| 522 | (Bug#17163). */ | ||
| 523 | unit = FRAME_COLUMN_WIDTH (f); | ||
| 524 | if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0) | ||
| 525 | FRAME_CONFIG_SCROLL_BAR_COLS (f) | ||
| 526 | = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + unit - 1) / unit; | ||
| 527 | else | ||
| 528 | FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + unit - 1) / unit; | ||
| 529 | |||
| 530 | |||
| 531 | /* Don't change the size of a tip frame; there's no point in doing it | ||
| 532 | because it's done in Fx_show_tip, and it leads to problems because | ||
| 533 | the tip frame has no widget. */ | ||
| 534 | if (FRAME_ANDROID_WINDOW (f) != 0 && !FRAME_TOOLTIP_P (f)) | ||
| 535 | adjust_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f), | ||
| 536 | FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 3, | ||
| 537 | false, Qfont); | ||
| 538 | |||
| 539 | return font_object; | ||
| 540 | } | ||
| 541 | |||
| 542 | static bool | ||
| 543 | android_bitmap_icon (struct frame *f, Lisp_Object file) | ||
| 544 | { | ||
| 545 | /* TODO */ | ||
| 546 | return false; | ||
| 547 | } | ||
| 548 | |||
| 549 | static void | ||
| 550 | android_free_pixmap_hook (struct frame *f, Emacs_Pixmap pixmap) | ||
| 551 | { | ||
| 552 | android_free_pixmap (pixmap); | ||
| 553 | } | ||
| 554 | |||
| 555 | void | ||
| 556 | android_free_frame_resources (struct frame *f) | ||
| 557 | { | ||
| 558 | struct android_display_info *dpyinfo; | ||
| 559 | Mouse_HLInfo *hlinfo; | ||
| 560 | |||
| 561 | dpyinfo = FRAME_DISPLAY_INFO (f); | ||
| 562 | hlinfo = &dpyinfo->mouse_highlight; | ||
| 563 | |||
| 564 | block_input (); | ||
| 565 | free_frame_faces (f); | ||
| 566 | |||
| 567 | /* FRAME_ANDROID_WINDOW can be 0 if frame creation failed. */ | ||
| 568 | if (FRAME_ANDROID_WINDOW (f)) | ||
| 569 | android_destroy_window (FRAME_ANDROID_WINDOW (f)); | ||
| 570 | |||
| 571 | android_free_gcs (f); | ||
| 572 | |||
| 573 | /* Free extra GCs allocated by android_setup_relief_colors. */ | ||
| 574 | if (f->output_data.android->white_relief.gc) | ||
| 575 | { | ||
| 576 | android_free_gc (f->output_data.android->white_relief.gc); | ||
| 577 | f->output_data.android->white_relief.gc = 0; | ||
| 578 | } | ||
| 579 | if (f->output_data.android->black_relief.gc) | ||
| 580 | { | ||
| 581 | android_free_gc (f->output_data.android->black_relief.gc); | ||
| 582 | f->output_data.android->black_relief.gc = 0; | ||
| 583 | } | ||
| 584 | |||
| 585 | if (f == dpyinfo->focus_frame) | ||
| 586 | dpyinfo->focus_frame = 0; | ||
| 587 | if (f == dpyinfo->highlight_frame) | ||
| 588 | dpyinfo->highlight_frame = 0; | ||
| 589 | if (f == hlinfo->mouse_face_mouse_frame) | ||
| 590 | reset_mouse_highlight (hlinfo); | ||
| 591 | |||
| 592 | unblock_input (); | ||
| 593 | } | ||
| 594 | |||
| 595 | static void | ||
| 596 | android_delete_frame (struct frame *f) | ||
| 597 | { | ||
| 598 | android_free_frame_resources (f); | ||
| 599 | xfree (f->output_data.android); | ||
| 600 | f->output_data.android = NULL; | ||
| 601 | } | ||
| 602 | |||
| 603 | static void | ||
| 604 | android_delete_terminal (struct terminal *terminal) | ||
| 605 | { | ||
| 606 | error ("Cannot terminate connection to Android display server"); | ||
| 607 | } | ||
| 608 | |||
| 609 | |||
| 610 | |||
| 611 | /* RIF functions. */ | ||
| 612 | |||
| 613 | static void | ||
| 614 | android_scroll_run (struct window *w, struct run *run) | ||
| 615 | { | ||
| 616 | struct frame *f = XFRAME (w->frame); | ||
| 617 | int x, y, width, height, from_y, to_y, bottom_y; | ||
| 618 | |||
| 619 | /* Get frame-relative bounding box of the text display area of W, | ||
| 620 | without mode lines. Include in this box the left and right | ||
| 621 | fringe of W. */ | ||
| 622 | window_box (w, ANY_AREA, &x, &y, &width, &height); | ||
| 623 | |||
| 624 | from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y); | ||
| 625 | to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y); | ||
| 626 | bottom_y = y + height; | ||
| 627 | |||
| 628 | if (to_y < from_y) | ||
| 629 | { | ||
| 630 | /* Scrolling up. Make sure we don't copy part of the mode | ||
| 631 | line at the bottom. */ | ||
| 632 | if (from_y + run->height > bottom_y) | ||
| 633 | height = bottom_y - from_y; | ||
| 634 | else | ||
| 635 | height = run->height; | ||
| 636 | } | ||
| 637 | else | ||
| 638 | { | ||
| 639 | /* Scrolling down. Make sure we don't copy over the mode line. | ||
| 640 | at the bottom. */ | ||
| 641 | if (to_y + run->height > bottom_y) | ||
| 642 | height = bottom_y - to_y; | ||
| 643 | else | ||
| 644 | height = run->height; | ||
| 645 | } | ||
| 646 | |||
| 647 | block_input (); | ||
| 648 | |||
| 649 | /* Cursor off. Will be switched on again in gui_update_window_end. */ | ||
| 650 | gui_clear_cursor (w); | ||
| 651 | |||
| 652 | android_copy_area (FRAME_ANDROID_WINDOW (f), | ||
| 653 | FRAME_ANDROID_WINDOW (f), | ||
| 654 | f->output_data.android->normal_gc, | ||
| 655 | x, from_y, width, height, x, to_y); | ||
| 656 | |||
| 657 | unblock_input (); | ||
| 658 | } | ||
| 659 | |||
| 660 | static void | ||
| 661 | android_after_update_window_line (struct window *w, struct glyph_row *desired_row) | ||
| 662 | { | ||
| 663 | eassert (w); | ||
| 664 | |||
| 665 | if (!desired_row->mode_line_p && !w->pseudo_window_p) | ||
| 666 | desired_row->redraw_fringe_bitmaps_p = true; | ||
| 667 | } | ||
| 668 | |||
| 669 | static void | ||
| 670 | android_flip_and_flush (struct frame *f) | ||
| 671 | { | ||
| 672 | block_input (); | ||
| 673 | show_back_buffer (f); | ||
| 674 | |||
| 675 | /* The frame is complete again as its contents were just | ||
| 676 | flushed. */ | ||
| 677 | FRAME_ANDROID_COMPLETE_P (f) = true; | ||
| 678 | unblock_input (); | ||
| 679 | } | ||
| 680 | |||
| 681 | static void | ||
| 682 | android_clear_rectangle (struct frame *f, struct android_gc *gc, int x, | ||
| 683 | int y, int width, int height) | ||
| 684 | { | ||
| 685 | struct android_gc_values xgcv; | ||
| 686 | |||
| 687 | android_get_gc_values (gc, (ANDROID_GC_BACKGROUND | ||
| 688 | | ANDROID_GC_FOREGROUND), | ||
| 689 | &xgcv); | ||
| 690 | android_set_foreground (gc, xgcv.background); | ||
| 691 | android_fill_rectangle (FRAME_ANDROID_WINDOW (f), gc, | ||
| 692 | x, y, width, height); | ||
| 693 | android_set_foreground (gc, xgcv.foreground); | ||
| 694 | } | ||
| 695 | |||
| 696 | static void | ||
| 697 | android_reset_clip_rectangles (struct frame *f, struct android_gc *gc) | ||
| 698 | { | ||
| 699 | android_set_clip_mask (gc, ANDROID_NONE); | ||
| 700 | } | ||
| 701 | |||
| 702 | static void | ||
| 703 | android_clip_to_row (struct window *w, struct glyph_row *row, | ||
| 704 | enum glyph_row_area area, struct android_gc *gc) | ||
| 705 | { | ||
| 706 | struct android_rectangle clip_rect; | ||
| 707 | int window_x, window_y, window_width; | ||
| 708 | |||
| 709 | window_box (w, area, &window_x, &window_y, &window_width, 0); | ||
| 710 | |||
| 711 | clip_rect.x = window_x; | ||
| 712 | clip_rect.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y)); | ||
| 713 | clip_rect.y = max (clip_rect.y, window_y); | ||
| 714 | clip_rect.width = window_width; | ||
| 715 | clip_rect.height = row->visible_height; | ||
| 716 | |||
| 717 | android_set_clip_rectangles (gc, 0, 0, &clip_rect, 1); | ||
| 718 | } | ||
| 719 | |||
| 720 | static void | ||
| 721 | android_draw_fringe_bitmap (struct window *w, struct glyph_row *row, | ||
| 722 | struct draw_fringe_bitmap_params *p) | ||
| 723 | { | ||
| 724 | struct frame *f = XFRAME (WINDOW_FRAME (w)); | ||
| 725 | struct android_gc *gc = f->output_data.android->normal_gc; | ||
| 726 | struct face *face = p->face; | ||
| 727 | |||
| 728 | /* Must clip because of partially visible lines. */ | ||
| 729 | android_clip_to_row (w, row, ANY_AREA, gc); | ||
| 730 | |||
| 731 | if (p->bx >= 0 && !p->overlay_p) | ||
| 732 | { | ||
| 733 | /* In case the same realized face is used for fringes and for | ||
| 734 | something displayed in the text (e.g. face `region' on | ||
| 735 | mono-displays, the fill style may have been changed to | ||
| 736 | ANDROID_FILL_SOLID in | ||
| 737 | android_draw_glyph_string_background. */ | ||
| 738 | if (face->stipple) | ||
| 739 | { | ||
| 740 | android_set_fill_style (face->gc, ANDROID_FILL_OPAQUE_STIPPLED); | ||
| 741 | android_fill_rectangle (FRAME_ANDROID_WINDOW (f), face->gc, | ||
| 742 | p->bx, p->by, p->nx, p->ny); | ||
| 743 | android_set_fill_style (face->gc, ANDROID_FILL_SOLID); | ||
| 744 | |||
| 745 | row->stipple_p = true; | ||
| 746 | } | ||
| 747 | else | ||
| 748 | { | ||
| 749 | android_set_background (face->gc, face->background); | ||
| 750 | android_clear_rectangle (f, face->gc, p->bx, p->by, p->nx, p->ny); | ||
| 751 | android_set_foreground (face->gc, face->foreground); | ||
| 752 | } | ||
| 753 | } | ||
| 754 | |||
| 755 | if (p->which) | ||
| 756 | { | ||
| 757 | android_drawable drawable; | ||
| 758 | char *bits; | ||
| 759 | android_pixmap pixmap, clipmask; | ||
| 760 | struct android_gc_values gcv; | ||
| 761 | unsigned long background, cursor_pixel; | ||
| 762 | int depth; | ||
| 763 | |||
| 764 | drawable = FRAME_ANDROID_WINDOW (f); | ||
| 765 | clipmask = ANDROID_NONE; | ||
| 766 | background = face->background; | ||
| 767 | cursor_pixel = f->output_data.android->cursor_pixel; | ||
| 768 | depth = FRAME_DISPLAY_INFO (f)->n_planes; | ||
| 769 | |||
| 770 | if (p->wd > 8) | ||
| 771 | bits = (char *) (p->bits + p->dh); | ||
| 772 | else | ||
| 773 | bits = (char *) p->bits + p->dh; | ||
| 774 | |||
| 775 | pixmap = android_create_pixmap_from_bitmap_data (bits, p->wd, p->h, | ||
| 776 | (p->cursor_p | ||
| 777 | ? (p->overlay_p | ||
| 778 | ? face->background | ||
| 779 | : cursor_pixel) | ||
| 780 | : face->foreground), | ||
| 781 | background, depth); | ||
| 782 | |||
| 783 | if (p->overlay_p) | ||
| 784 | { | ||
| 785 | clipmask = android_create_pixmap_from_bitmap_data (bits, p->wd, p->h, | ||
| 786 | 1, 0, 0); | ||
| 787 | |||
| 788 | gcv.clip_mask = clipmask; | ||
| 789 | gcv.clip_x_origin = p->x; | ||
| 790 | gcv.clip_y_origin = p->y; | ||
| 791 | android_change_gc (gc, (ANDROID_GC_CLIP_MASK | ||
| 792 | | ANDROID_GC_CLIP_X_ORIGIN | ||
| 793 | | ANDROID_GC_CLIP_Y_ORIGIN), | ||
| 794 | &gcv); | ||
| 795 | } | ||
| 796 | |||
| 797 | android_copy_area (pixmap, drawable, gc, 0, 0, p->wd, p->h, | ||
| 798 | p->x, p->y); | ||
| 799 | android_free_pixmap (pixmap); | ||
| 800 | |||
| 801 | if (p->overlay_p) | ||
| 802 | { | ||
| 803 | gcv.clip_mask = ANDROID_NONE; | ||
| 804 | android_change_gc (gc, ANDROID_GC_CLIP_MASK, &gcv); | ||
| 805 | android_free_pixmap (clipmask); | ||
| 806 | } | ||
| 807 | } | ||
| 808 | |||
| 809 | android_reset_clip_rectangles (f, gc); | ||
| 810 | } | ||
| 811 | |||
| 812 | /* Set S->gc to a suitable GC for drawing glyph string S in cursor | ||
| 813 | face. */ | ||
| 814 | |||
| 815 | static void | ||
| 816 | android_set_cursor_gc (struct glyph_string *s) | ||
| 817 | { | ||
| 818 | if (s->font == FRAME_FONT (s->f) | ||
| 819 | && s->face->background == FRAME_BACKGROUND_PIXEL (s->f) | ||
| 820 | && s->face->foreground == FRAME_FOREGROUND_PIXEL (s->f) | ||
| 821 | && !s->cmp) | ||
| 822 | s->gc = s->f->output_data.android->cursor_gc; | ||
| 823 | else | ||
| 824 | { | ||
| 825 | /* Cursor on non-default face: must merge. */ | ||
| 826 | struct android_gc_values xgcv; | ||
| 827 | unsigned long mask; | ||
| 828 | |||
| 829 | xgcv.background = s->f->output_data.android->cursor_pixel; | ||
| 830 | xgcv.foreground = s->face->background; | ||
| 831 | |||
| 832 | /* If the glyph would be invisible, try a different foreground. */ | ||
| 833 | if (xgcv.foreground == xgcv.background) | ||
| 834 | xgcv.foreground = s->face->foreground; | ||
| 835 | if (xgcv.foreground == xgcv.background) | ||
| 836 | xgcv.foreground = s->f->output_data.android->cursor_foreground_pixel; | ||
| 837 | if (xgcv.foreground == xgcv.background) | ||
| 838 | xgcv.foreground = s->face->foreground; | ||
| 839 | |||
| 840 | /* Make sure the cursor is distinct from text in this face. */ | ||
| 841 | if (xgcv.background == s->face->background | ||
| 842 | && xgcv.foreground == s->face->foreground) | ||
| 843 | { | ||
| 844 | xgcv.background = s->face->foreground; | ||
| 845 | xgcv.foreground = s->face->background; | ||
| 846 | } | ||
| 847 | |||
| 848 | mask = (ANDROID_GC_FOREGROUND | ANDROID_GC_BACKGROUND); | ||
| 849 | |||
| 850 | if (FRAME_DISPLAY_INFO (s->f)->scratch_cursor_gc) | ||
| 851 | android_change_gc (FRAME_DISPLAY_INFO (s->f)->scratch_cursor_gc, | ||
| 852 | mask, &xgcv); | ||
| 853 | else | ||
| 854 | FRAME_DISPLAY_INFO (s->f)->scratch_cursor_gc | ||
| 855 | = android_create_gc (mask, &xgcv); | ||
| 856 | |||
| 857 | s->gc = FRAME_DISPLAY_INFO (s->f)->scratch_cursor_gc; | ||
| 858 | } | ||
| 859 | } | ||
| 860 | |||
| 861 | |||
| 862 | /* Set up S->gc of glyph string S for drawing text in mouse face. */ | ||
| 863 | |||
| 864 | static void | ||
| 865 | android_set_mouse_face_gc (struct glyph_string *s) | ||
| 866 | { | ||
| 867 | if (s->font == s->face->font) | ||
| 868 | s->gc = s->face->gc; | ||
| 869 | else | ||
| 870 | { | ||
| 871 | /* Otherwise construct scratch_cursor_gc with values from FACE | ||
| 872 | except for FONT. */ | ||
| 873 | struct android_gc_values xgcv; | ||
| 874 | unsigned long mask; | ||
| 875 | |||
| 876 | xgcv.background = s->face->background; | ||
| 877 | xgcv.foreground = s->face->foreground; | ||
| 878 | |||
| 879 | mask = (ANDROID_GC_FOREGROUND | ANDROID_GC_BACKGROUND); | ||
| 880 | |||
| 881 | if (FRAME_DISPLAY_INFO (s->f)->scratch_cursor_gc) | ||
| 882 | android_change_gc (FRAME_DISPLAY_INFO (s->f)->scratch_cursor_gc, | ||
| 883 | mask, &xgcv); | ||
| 884 | else | ||
| 885 | FRAME_DISPLAY_INFO (s->f)->scratch_cursor_gc | ||
| 886 | = android_create_gc (mask, &xgcv); | ||
| 887 | |||
| 888 | s->gc = FRAME_DISPLAY_INFO (s->f)->scratch_cursor_gc; | ||
| 889 | } | ||
| 890 | |||
| 891 | eassert (s->gc != 0); | ||
| 892 | } | ||
| 893 | |||
| 894 | |||
| 895 | /* Set S->gc of glyph string S to a GC suitable for drawing a mode line. | ||
| 896 | Faces to use in the mode line have already been computed when the | ||
| 897 | matrix was built, so there isn't much to do, here. */ | ||
| 898 | |||
| 899 | static void | ||
| 900 | android_set_mode_line_face_gc (struct glyph_string *s) | ||
| 901 | { | ||
| 902 | s->gc = s->face->gc; | ||
| 903 | } | ||
| 904 | |||
| 905 | /* Set S->gc of glyph string S for drawing that glyph string. Set | ||
| 906 | S->stippled_p to a non-zero value if the face of S has a stipple | ||
| 907 | pattern. */ | ||
| 908 | |||
| 909 | static void | ||
| 910 | android_set_glyph_string_gc (struct glyph_string *s) | ||
| 911 | { | ||
| 912 | prepare_face_for_display (s->f, s->face); | ||
| 913 | |||
| 914 | if (s->hl == DRAW_NORMAL_TEXT) | ||
| 915 | { | ||
| 916 | s->gc = s->face->gc; | ||
| 917 | s->stippled_p = s->face->stipple != 0; | ||
| 918 | } | ||
| 919 | else if (s->hl == DRAW_INVERSE_VIDEO) | ||
| 920 | { | ||
| 921 | android_set_mode_line_face_gc (s); | ||
| 922 | s->stippled_p = s->face->stipple != 0; | ||
| 923 | } | ||
| 924 | else if (s->hl == DRAW_CURSOR) | ||
| 925 | { | ||
| 926 | android_set_cursor_gc (s); | ||
| 927 | s->stippled_p = false; | ||
| 928 | } | ||
| 929 | else if (s->hl == DRAW_MOUSE_FACE) | ||
| 930 | { | ||
| 931 | android_set_mouse_face_gc (s); | ||
| 932 | s->stippled_p = s->face->stipple != 0; | ||
| 933 | } | ||
| 934 | else if (s->hl == DRAW_IMAGE_RAISED | ||
| 935 | || s->hl == DRAW_IMAGE_SUNKEN) | ||
| 936 | { | ||
| 937 | s->gc = s->face->gc; | ||
| 938 | s->stippled_p = s->face->stipple != 0; | ||
| 939 | } | ||
| 940 | else | ||
| 941 | emacs_abort (); | ||
| 942 | |||
| 943 | /* GC must have been set. */ | ||
| 944 | eassert (s->gc != 0); | ||
| 945 | } | ||
| 946 | |||
| 947 | |||
| 948 | /* Set clipping for output of glyph string S. S may be part of a mode | ||
| 949 | line or menu if we don't have X toolkit support. */ | ||
| 950 | |||
| 951 | static void | ||
| 952 | android_set_glyph_string_clipping (struct glyph_string *s) | ||
| 953 | { | ||
| 954 | struct android_rectangle *r = s->clip; | ||
| 955 | int n = get_glyph_string_clip_rects (s, r, 2); | ||
| 956 | |||
| 957 | if (n > 0) | ||
| 958 | android_set_clip_rectangles (s->gc, 0, 0, r, n); | ||
| 959 | s->num_clips = n; | ||
| 960 | } | ||
| 961 | |||
| 962 | |||
| 963 | /* Set SRC's clipping for output of glyph string DST. This is called | ||
| 964 | when we are drawing DST's left_overhang or right_overhang only in | ||
| 965 | the area of SRC. */ | ||
| 966 | |||
| 967 | static void | ||
| 968 | android_set_glyph_string_clipping_exactly (struct glyph_string *src, | ||
| 969 | struct glyph_string *dst) | ||
| 970 | { | ||
| 971 | struct android_rectangle r; | ||
| 972 | |||
| 973 | r.x = src->x; | ||
| 974 | r.width = src->width; | ||
| 975 | r.y = src->y; | ||
| 976 | r.height = src->height; | ||
| 977 | dst->clip[0] = r; | ||
| 978 | dst->num_clips = 1; | ||
| 979 | android_set_clip_rectangles (dst->gc, 0, 0, &r, 1); | ||
| 980 | } | ||
| 981 | |||
| 982 | static void | ||
| 983 | android_compute_glyph_string_overhangs (struct glyph_string *s) | ||
| 984 | { | ||
| 985 | if (s->cmp == NULL | ||
| 986 | && (s->first_glyph->type == CHAR_GLYPH | ||
| 987 | || s->first_glyph->type == COMPOSITE_GLYPH)) | ||
| 988 | { | ||
| 989 | struct font_metrics metrics; | ||
| 990 | |||
| 991 | if (s->first_glyph->type == CHAR_GLYPH) | ||
| 992 | { | ||
| 993 | struct font *font = s->font; | ||
| 994 | font->driver->text_extents (font, s->char2b, s->nchars, &metrics); | ||
| 995 | } | ||
| 996 | else | ||
| 997 | { | ||
| 998 | Lisp_Object gstring = composition_gstring_from_id (s->cmp_id); | ||
| 999 | |||
| 1000 | composition_gstring_width (gstring, s->cmp_from, s->cmp_to, &metrics); | ||
| 1001 | } | ||
| 1002 | s->right_overhang = (metrics.rbearing > metrics.width | ||
| 1003 | ? metrics.rbearing - metrics.width : 0); | ||
| 1004 | s->left_overhang = metrics.lbearing < 0 ? - metrics.lbearing : 0; | ||
| 1005 | } | ||
| 1006 | else if (s->cmp) | ||
| 1007 | { | ||
| 1008 | s->right_overhang = s->cmp->rbearing - s->cmp->pixel_width; | ||
| 1009 | s->left_overhang = - s->cmp->lbearing; | ||
| 1010 | } | ||
| 1011 | } | ||
| 1012 | |||
| 1013 | static void | ||
| 1014 | android_clear_glyph_string_rect (struct glyph_string *s, int x, int y, | ||
| 1015 | int w, int h) | ||
| 1016 | { | ||
| 1017 | android_clear_rectangle (s->f, s->gc, x, y, w, h); | ||
| 1018 | } | ||
| 1019 | |||
| 1020 | static void | ||
| 1021 | android_draw_glyph_string_background (struct glyph_string *s, bool force_p) | ||
| 1022 | { | ||
| 1023 | /* Nothing to do if background has already been drawn or if it | ||
| 1024 | shouldn't be drawn in the first place. */ | ||
| 1025 | if (!s->background_filled_p) | ||
| 1026 | { | ||
| 1027 | int box_line_width = max (s->face->box_horizontal_line_width, 0); | ||
| 1028 | |||
| 1029 | if (s->stippled_p) | ||
| 1030 | { | ||
| 1031 | /* Fill background with a stipple pattern. */ | ||
| 1032 | android_set_fill_style (s->gc, ANDROID_FILL_OPAQUE_STIPPLED); | ||
| 1033 | android_fill_rectangle (FRAME_ANDROID_WINDOW (s->f), s->gc, | ||
| 1034 | s->x, s->y + box_line_width, | ||
| 1035 | s->background_width, | ||
| 1036 | s->height - 2 * box_line_width); | ||
| 1037 | android_set_fill_style (s->gc, ANDROID_FILL_SOLID); | ||
| 1038 | s->background_filled_p = true; | ||
| 1039 | } | ||
| 1040 | else if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width | ||
| 1041 | /* When xdisp.c ignores FONT_HEIGHT, we cannot trust | ||
| 1042 | font dimensions, since the actual glyphs might be | ||
| 1043 | much smaller. So in that case we always clear the | ||
| 1044 | rectangle with background color. */ | ||
| 1045 | || FONT_TOO_HIGH (s->font) | ||
| 1046 | || s->font_not_found_p | ||
| 1047 | || s->extends_to_end_of_line_p | ||
| 1048 | || force_p) | ||
| 1049 | { | ||
| 1050 | android_clear_glyph_string_rect (s, s->x, s->y + box_line_width, | ||
| 1051 | s->background_width, | ||
| 1052 | s->height - 2 * box_line_width); | ||
| 1053 | s->background_filled_p = true; | ||
| 1054 | } | ||
| 1055 | } | ||
| 1056 | } | ||
| 1057 | |||
| 1058 | static void | ||
| 1059 | android_fill_triangle (struct frame *f, struct android_gc *gc, | ||
| 1060 | struct android_point point1, | ||
| 1061 | struct android_point point2, | ||
| 1062 | struct android_point point3) | ||
| 1063 | { | ||
| 1064 | struct android_point abc[3]; | ||
| 1065 | |||
| 1066 | abc[0] = point1; | ||
| 1067 | abc[1] = point2; | ||
| 1068 | abc[2] = point3; | ||
| 1069 | |||
| 1070 | android_fill_polygon (FRAME_ANDROID_WINDOW (f), | ||
| 1071 | gc, abc, 3, ANDROID_CONVEX, | ||
| 1072 | ANDROID_COORD_MODE_ORIGIN); | ||
| 1073 | } | ||
| 1074 | |||
| 1075 | static struct android_point | ||
| 1076 | android_make_point (int x, int y) | ||
| 1077 | { | ||
| 1078 | struct android_point pt; | ||
| 1079 | |||
| 1080 | pt.x = x; | ||
| 1081 | pt.y = y; | ||
| 1082 | |||
| 1083 | return pt; | ||
| 1084 | } | ||
| 1085 | |||
| 1086 | static bool | ||
| 1087 | android_inside_rect_p (struct android_rectangle *rects, int nrects, int x, | ||
| 1088 | int y) | ||
| 1089 | { | ||
| 1090 | int i; | ||
| 1091 | |||
| 1092 | for (i = 0; i < nrects; ++i) | ||
| 1093 | { | ||
| 1094 | if (x >= rects[i].x && y >= rects[i].y | ||
| 1095 | && x < rects[i].x + rects[i].width | ||
| 1096 | && y < rects[i].y + rects[i].height) | ||
| 1097 | return true; | ||
| 1098 | } | ||
| 1099 | |||
| 1100 | return false; | ||
| 1101 | } | ||
| 1102 | |||
| 1103 | static void | ||
| 1104 | android_clear_point (struct frame *f, struct android_gc *gc, | ||
| 1105 | int x, int y) | ||
| 1106 | { | ||
| 1107 | struct android_gc_values xgcv; | ||
| 1108 | |||
| 1109 | android_get_gc_values (gc, ANDROID_GC_BACKGROUND | ANDROID_GC_FOREGROUND, | ||
| 1110 | &xgcv); | ||
| 1111 | android_set_foreground (gc, xgcv.background); | ||
| 1112 | android_draw_point (FRAME_ANDROID_WINDOW (f), gc, x, y); | ||
| 1113 | android_set_foreground (gc, xgcv.foreground); | ||
| 1114 | } | ||
| 1115 | |||
| 1116 | static void | ||
| 1117 | android_draw_relief_rect (struct frame *f, int left_x, int top_y, int right_x, | ||
| 1118 | int bottom_y, int hwidth, int vwidth, bool raised_p, | ||
| 1119 | bool top_p, bool bot_p, bool left_p, bool right_p, | ||
| 1120 | struct android_rectangle *clip_rect) | ||
| 1121 | { | ||
| 1122 | struct android_gc *gc, *white_gc, *black_gc, *normal_gc; | ||
| 1123 | android_drawable drawable; | ||
| 1124 | |||
| 1125 | /* This code is more complicated than it has to be, because of two | ||
| 1126 | minor hacks to make the boxes look nicer: (i) if width > 1, draw | ||
| 1127 | the outermost line using the black relief. (ii) Omit the four | ||
| 1128 | corner pixels. */ | ||
| 1129 | |||
| 1130 | white_gc = f->output_data.android->white_relief.gc; | ||
| 1131 | black_gc = f->output_data.android->black_relief.gc; | ||
| 1132 | normal_gc = f->output_data.android->normal_gc; | ||
| 1133 | |||
| 1134 | drawable = FRAME_ANDROID_WINDOW (f); | ||
| 1135 | |||
| 1136 | android_set_clip_rectangles (white_gc, 0, 0, clip_rect, 1); | ||
| 1137 | android_set_clip_rectangles (black_gc, 0, 0, clip_rect, 1); | ||
| 1138 | |||
| 1139 | if (raised_p) | ||
| 1140 | gc = white_gc; | ||
| 1141 | else | ||
| 1142 | gc = black_gc; | ||
| 1143 | |||
| 1144 | /* Draw lines. */ | ||
| 1145 | |||
| 1146 | if (top_p) | ||
| 1147 | android_fill_rectangle (FRAME_ANDROID_WINDOW (f), gc, left_x, top_y, | ||
| 1148 | right_x - left_x + 1, hwidth); | ||
| 1149 | |||
| 1150 | if (left_p) | ||
| 1151 | android_fill_rectangle (FRAME_ANDROID_WINDOW (f), gc, left_x, top_y, | ||
| 1152 | vwidth, bottom_y - top_y + 1); | ||
| 1153 | |||
| 1154 | if (raised_p) | ||
| 1155 | gc = black_gc; | ||
| 1156 | else | ||
| 1157 | gc = white_gc; | ||
| 1158 | |||
| 1159 | if (bot_p) | ||
| 1160 | android_fill_rectangle (FRAME_ANDROID_WINDOW (f), gc, left_x, | ||
| 1161 | bottom_y - hwidth + 1, | ||
| 1162 | right_x - left_x + 1, hwidth); | ||
| 1163 | |||
| 1164 | if (right_p) | ||
| 1165 | android_fill_rectangle (FRAME_ANDROID_WINDOW (f), gc, | ||
| 1166 | right_x - vwidth + 1, | ||
| 1167 | top_y, vwidth, bottom_y - top_y + 1); | ||
| 1168 | |||
| 1169 | /* Draw corners. */ | ||
| 1170 | |||
| 1171 | if (bot_p && left_p) | ||
| 1172 | android_fill_triangle (f, raised_p ? white_gc : black_gc, | ||
| 1173 | android_make_point (left_x, bottom_y - hwidth), | ||
| 1174 | android_make_point (left_x + vwidth, | ||
| 1175 | bottom_y - hwidth), | ||
| 1176 | android_make_point (left_x, bottom_y)); | ||
| 1177 | |||
| 1178 | if (top_p && right_p) | ||
| 1179 | android_fill_triangle (f, raised_p ? white_gc : black_gc, | ||
| 1180 | android_make_point (right_x - vwidth, top_y), | ||
| 1181 | android_make_point (right_x, top_y), | ||
| 1182 | android_make_point (right_x - vwidth, | ||
| 1183 | top_y + hwidth)); | ||
| 1184 | |||
| 1185 | /* Draw outer line. */ | ||
| 1186 | |||
| 1187 | if (top_p && left_p && bot_p && right_p | ||
| 1188 | && hwidth > 1 && vwidth > 1) | ||
| 1189 | android_draw_rectangle (FRAME_ANDROID_WINDOW (f), | ||
| 1190 | black_gc, left_x, top_y, | ||
| 1191 | right_x - left_x, bottom_y - top_y); | ||
| 1192 | else | ||
| 1193 | { | ||
| 1194 | if (top_p && hwidth > 1) | ||
| 1195 | android_draw_line (drawable, black_gc, left_x, top_y, | ||
| 1196 | right_x + 1, top_y); | ||
| 1197 | |||
| 1198 | if (bot_p && hwidth > 1) | ||
| 1199 | android_draw_line (drawable, black_gc, left_x, bottom_y, | ||
| 1200 | right_x + 1, bottom_y); | ||
| 1201 | |||
| 1202 | if (left_p && vwidth > 1) | ||
| 1203 | android_draw_line (drawable, black_gc, left_x, top_y, | ||
| 1204 | left_x, bottom_y + 1); | ||
| 1205 | |||
| 1206 | if (right_p && vwidth > 1) | ||
| 1207 | android_draw_line (drawable, black_gc, right_x, top_y, | ||
| 1208 | right_x, bottom_y + 1); | ||
| 1209 | } | ||
| 1210 | |||
| 1211 | /* Erase corners. */ | ||
| 1212 | |||
| 1213 | if (hwidth > 1 && vwidth > 1) | ||
| 1214 | { | ||
| 1215 | if (left_p && top_p && android_inside_rect_p (clip_rect, 1, | ||
| 1216 | left_x, top_y)) | ||
| 1217 | android_clear_point (f, normal_gc, left_x, top_y); | ||
| 1218 | |||
| 1219 | if (left_p && bot_p && android_inside_rect_p (clip_rect, 1, | ||
| 1220 | left_x, bottom_y)) | ||
| 1221 | android_clear_point (f, normal_gc, left_x, bottom_y); | ||
| 1222 | |||
| 1223 | if (right_p && top_p && android_inside_rect_p (clip_rect, 1, | ||
| 1224 | right_x, top_y)) | ||
| 1225 | android_clear_point (f, normal_gc, right_x, top_y); | ||
| 1226 | |||
| 1227 | if (right_p && bot_p && android_inside_rect_p (clip_rect, 1, | ||
| 1228 | right_x, bottom_y)) | ||
| 1229 | android_clear_point (f, normal_gc, right_x, bottom_y); | ||
| 1230 | } | ||
| 1231 | |||
| 1232 | android_reset_clip_rectangles (f, white_gc); | ||
| 1233 | android_reset_clip_rectangles (f, black_gc); | ||
| 1234 | } | ||
| 1235 | |||
| 1236 | static void | ||
| 1237 | android_draw_box_rect (struct glyph_string *s, | ||
| 1238 | int left_x, int top_y, int right_x, int bottom_y, | ||
| 1239 | int hwidth, int vwidth, bool left_p, bool right_p, | ||
| 1240 | struct android_rectangle *clip_rect) | ||
| 1241 | { | ||
| 1242 | struct android_gc_values xgcv; | ||
| 1243 | |||
| 1244 | android_get_gc_values (s->gc, ANDROID_GC_FOREGROUND, &xgcv); | ||
| 1245 | android_set_foreground (s->gc, s->face->box_color); | ||
| 1246 | android_set_clip_rectangles (s->gc, 0, 0, clip_rect, 1); | ||
| 1247 | |||
| 1248 | /* Top. */ | ||
| 1249 | android_fill_rectangle (FRAME_ANDROID_WINDOW (s->f), s->gc, left_x, | ||
| 1250 | left_x, right_x - left_x + 1, hwidth); | ||
| 1251 | |||
| 1252 | /* Left. */ | ||
| 1253 | if (left_p) | ||
| 1254 | android_fill_rectangle (FRAME_ANDROID_WINDOW (s->f), s->gc, left_x, | ||
| 1255 | top_y, vwidth, bottom_y - top_y + 1); | ||
| 1256 | |||
| 1257 | /* Bottom. */ | ||
| 1258 | android_fill_rectangle (FRAME_ANDROID_WINDOW (s->f), s->gc, left_x, | ||
| 1259 | bottom_y - hwidth + 1, right_x - left_x + 1, | ||
| 1260 | hwidth); | ||
| 1261 | |||
| 1262 | /* Right. */ | ||
| 1263 | if (right_p) | ||
| 1264 | android_fill_rectangle (FRAME_ANDROID_WINDOW (s->f), s->gc, | ||
| 1265 | right_x - vwidth + 1, top_y, vwidth, | ||
| 1266 | bottom_y - top_y + 1); | ||
| 1267 | |||
| 1268 | android_set_foreground (s->gc, xgcv.foreground); | ||
| 1269 | android_reset_clip_rectangles (s->f, s->gc); | ||
| 1270 | } | ||
| 1271 | |||
| 1272 | #define HIGHLIGHT_COLOR_DARK_BOOST_LIMIT 48000 | ||
| 1273 | |||
| 1274 | static bool | ||
| 1275 | android_alloc_lighter_color (struct frame *f, unsigned long *pixel, | ||
| 1276 | double factor, int delta) | ||
| 1277 | { | ||
| 1278 | Emacs_Color color, new; | ||
| 1279 | long bright; | ||
| 1280 | bool success_p; | ||
| 1281 | |||
| 1282 | /* Get RGB color values. */ | ||
| 1283 | color.pixel = *pixel; | ||
| 1284 | android_query_colors (f, &color, 1); | ||
| 1285 | |||
| 1286 | /* Change RGB values by specified FACTOR. Avoid overflow! */ | ||
| 1287 | eassert (factor >= 0); | ||
| 1288 | new.red = min (0xffff, factor * color.red); | ||
| 1289 | new.green = min (0xffff, factor * color.green); | ||
| 1290 | new.blue = min (0xffff, factor * color.blue); | ||
| 1291 | |||
| 1292 | /* Calculate brightness of COLOR. */ | ||
| 1293 | bright = (2 * color.red + 3 * color.green + color.blue) / 6; | ||
| 1294 | |||
| 1295 | /* We only boost colors that are darker than | ||
| 1296 | HIGHLIGHT_COLOR_DARK_BOOST_LIMIT. */ | ||
| 1297 | if (bright < HIGHLIGHT_COLOR_DARK_BOOST_LIMIT) | ||
| 1298 | /* Make an additive adjustment to NEW, because it's dark enough so | ||
| 1299 | that scaling by FACTOR alone isn't enough. */ | ||
| 1300 | { | ||
| 1301 | /* How far below the limit this color is (0 - 1, 1 being darker). */ | ||
| 1302 | double dimness = 1 - (double) bright / HIGHLIGHT_COLOR_DARK_BOOST_LIMIT; | ||
| 1303 | /* The additive adjustment. */ | ||
| 1304 | int min_delta = delta * dimness * factor / 2; | ||
| 1305 | |||
| 1306 | if (factor < 1) | ||
| 1307 | { | ||
| 1308 | new.red = max (0, new.red - min_delta); | ||
| 1309 | new.green = max (0, new.green - min_delta); | ||
| 1310 | new.blue = max (0, new.blue - min_delta); | ||
| 1311 | } | ||
| 1312 | else | ||
| 1313 | { | ||
| 1314 | new.red = min (0xffff, min_delta + new.red); | ||
| 1315 | new.green = min (0xffff, min_delta + new.green); | ||
| 1316 | new.blue = min (0xffff, min_delta + new.blue); | ||
| 1317 | } | ||
| 1318 | } | ||
| 1319 | |||
| 1320 | /* Try to allocate the color. */ | ||
| 1321 | success_p = android_alloc_nearest_color (f, &new); | ||
| 1322 | |||
| 1323 | if (success_p) | ||
| 1324 | { | ||
| 1325 | if (new.pixel == *pixel) | ||
| 1326 | { | ||
| 1327 | /* If we end up with the same color as before, try adding | ||
| 1328 | delta to the RGB values. */ | ||
| 1329 | new.red = min (0xffff, delta + color.red); | ||
| 1330 | new.green = min (0xffff, delta + color.green); | ||
| 1331 | new.blue = min (0xffff, delta + color.blue); | ||
| 1332 | success_p = android_alloc_nearest_color (f, &new); | ||
| 1333 | } | ||
| 1334 | else | ||
| 1335 | success_p = true; | ||
| 1336 | |||
| 1337 | *pixel = new.pixel; | ||
| 1338 | } | ||
| 1339 | |||
| 1340 | return success_p; | ||
| 1341 | } | ||
| 1342 | |||
| 1343 | /* Set up the foreground color for drawing relief lines of glyph | ||
| 1344 | string S. RELIEF is a pointer to a struct relief containing the GC | ||
| 1345 | with which lines will be drawn. Use a color that is FACTOR or | ||
| 1346 | DELTA lighter or darker than the relief's background which is found | ||
| 1347 | in S->f->output_data.android->relief_background. If such a color | ||
| 1348 | cannot be allocated, use DEFAULT_PIXEL, instead. */ | ||
| 1349 | |||
| 1350 | static void | ||
| 1351 | android_setup_relief_color (struct frame *f, struct relief *relief, | ||
| 1352 | double factor, int delta, | ||
| 1353 | unsigned long default_pixel) | ||
| 1354 | { | ||
| 1355 | struct android_gc_values xgcv; | ||
| 1356 | struct android_output *di = f->output_data.android; | ||
| 1357 | unsigned long mask = ANDROID_GC_FOREGROUND; | ||
| 1358 | unsigned long pixel; | ||
| 1359 | unsigned long background = di->relief_background; | ||
| 1360 | struct android_display_info *dpyinfo = FRAME_DISPLAY_INFO (f); | ||
| 1361 | |||
| 1362 | if (relief->gc && relief->pixel != -1) | ||
| 1363 | relief->pixel = -1; | ||
| 1364 | |||
| 1365 | /* Allocate new color. */ | ||
| 1366 | xgcv.foreground = default_pixel; | ||
| 1367 | pixel = background; | ||
| 1368 | |||
| 1369 | if (dpyinfo->n_planes != 1 | ||
| 1370 | && android_alloc_lighter_color (f, &pixel, factor, delta)) | ||
| 1371 | xgcv.foreground = relief->pixel = pixel; | ||
| 1372 | |||
| 1373 | if (relief->gc == 0) | ||
| 1374 | relief->gc = android_create_gc (mask, &xgcv); | ||
| 1375 | else | ||
| 1376 | android_change_gc (relief->gc, mask, &xgcv); | ||
| 1377 | } | ||
| 1378 | |||
| 1379 | /* Set up colors for the relief lines around glyph string S. */ | ||
| 1380 | |||
| 1381 | static void | ||
| 1382 | android_setup_relief_colors (struct glyph_string *s) | ||
| 1383 | { | ||
| 1384 | struct android_output *di; | ||
| 1385 | unsigned long color; | ||
| 1386 | |||
| 1387 | di = s->f->output_data.android; | ||
| 1388 | |||
| 1389 | if (s->face->use_box_color_for_shadows_p) | ||
| 1390 | color = s->face->box_color; | ||
| 1391 | else if (s->first_glyph->type == IMAGE_GLYPH | ||
| 1392 | && s->img->pixmap | ||
| 1393 | && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0)) | ||
| 1394 | color = IMAGE_BACKGROUND (s->img, s->f, 0); | ||
| 1395 | else | ||
| 1396 | { | ||
| 1397 | struct android_gc_values xgcv; | ||
| 1398 | |||
| 1399 | /* Get the background color of the face. */ | ||
| 1400 | android_get_gc_values (s->gc, ANDROID_GC_BACKGROUND, &xgcv); | ||
| 1401 | color = xgcv.background; | ||
| 1402 | } | ||
| 1403 | |||
| 1404 | if (di->white_relief.gc == 0 | ||
| 1405 | || color != di->relief_background) | ||
| 1406 | { | ||
| 1407 | di->relief_background = color; | ||
| 1408 | android_setup_relief_color (s->f, &di->white_relief, 1.2, 0x8000, | ||
| 1409 | WHITE_PIX_DEFAULT (s->f)); | ||
| 1410 | android_setup_relief_color (s->f, &di->black_relief, 0.6, 0x4000, | ||
| 1411 | BLACK_PIX_DEFAULT (s->f)); | ||
| 1412 | } | ||
| 1413 | } | ||
| 1414 | |||
| 1415 | static void | ||
| 1416 | android_draw_glyph_string_box (struct glyph_string *s) | ||
| 1417 | { | ||
| 1418 | int hwidth, vwidth, left_x, right_x, top_y, bottom_y, last_x; | ||
| 1419 | bool raised_p, left_p, right_p; | ||
| 1420 | struct glyph *last_glyph; | ||
| 1421 | struct android_rectangle clip_rect; | ||
| 1422 | |||
| 1423 | last_x = ((s->row->full_width_p && !s->w->pseudo_window_p) | ||
| 1424 | ? WINDOW_RIGHT_EDGE_X (s->w) | ||
| 1425 | : window_box_right (s->w, s->area)); | ||
| 1426 | |||
| 1427 | /* The glyph that may have a right box line. For static | ||
| 1428 | compositions and images, the right-box flag is on the first glyph | ||
| 1429 | of the glyph string; for other types it's on the last glyph. */ | ||
| 1430 | if (s->cmp || s->img) | ||
| 1431 | last_glyph = s->first_glyph; | ||
| 1432 | else if (s->first_glyph->type == COMPOSITE_GLYPH | ||
| 1433 | && s->first_glyph->u.cmp.automatic) | ||
| 1434 | { | ||
| 1435 | /* For automatic compositions, we need to look up the last glyph | ||
| 1436 | in the composition. */ | ||
| 1437 | struct glyph *end = s->row->glyphs[s->area] + s->row->used[s->area]; | ||
| 1438 | struct glyph *g = s->first_glyph; | ||
| 1439 | for (last_glyph = g++; | ||
| 1440 | g < end && g->u.cmp.automatic && g->u.cmp.id == s->cmp_id | ||
| 1441 | && g->slice.cmp.to < s->cmp_to; | ||
| 1442 | last_glyph = g++) | ||
| 1443 | ; | ||
| 1444 | } | ||
| 1445 | else | ||
| 1446 | last_glyph = s->first_glyph + s->nchars - 1; | ||
| 1447 | |||
| 1448 | vwidth = eabs (s->face->box_vertical_line_width); | ||
| 1449 | hwidth = eabs (s->face->box_horizontal_line_width); | ||
| 1450 | raised_p = s->face->box == FACE_RAISED_BOX; | ||
| 1451 | left_x = s->x; | ||
| 1452 | right_x = (s->row->full_width_p && s->extends_to_end_of_line_p | ||
| 1453 | ? last_x - 1 | ||
| 1454 | : min (last_x, s->x + s->background_width) - 1); | ||
| 1455 | top_y = s->y; | ||
| 1456 | bottom_y = top_y + s->height - 1; | ||
| 1457 | |||
| 1458 | left_p = (s->first_glyph->left_box_line_p | ||
| 1459 | || (s->hl == DRAW_MOUSE_FACE | ||
| 1460 | && (s->prev == NULL | ||
| 1461 | || s->prev->hl != s->hl))); | ||
| 1462 | right_p = (last_glyph->right_box_line_p | ||
| 1463 | || (s->hl == DRAW_MOUSE_FACE | ||
| 1464 | && (s->next == NULL | ||
| 1465 | || s->next->hl != s->hl))); | ||
| 1466 | |||
| 1467 | get_glyph_string_clip_rect (s, &clip_rect); | ||
| 1468 | |||
| 1469 | if (s->face->box == FACE_SIMPLE_BOX) | ||
| 1470 | android_draw_box_rect (s, left_x, top_y, right_x, bottom_y, hwidth, | ||
| 1471 | vwidth, left_p, right_p, &clip_rect); | ||
| 1472 | else | ||
| 1473 | { | ||
| 1474 | android_setup_relief_colors (s); | ||
| 1475 | android_draw_relief_rect (s->f, left_x, top_y, right_x, bottom_y, hwidth, | ||
| 1476 | vwidth, raised_p, true, true, left_p, right_p, | ||
| 1477 | &clip_rect); | ||
| 1478 | } | ||
| 1479 | } | ||
| 1480 | |||
| 1481 | static void | ||
| 1482 | android_draw_glyph_string_bg_rect (struct glyph_string *s, int x, int y, | ||
| 1483 | int w, int h) | ||
| 1484 | { | ||
| 1485 | if (s->stippled_p) | ||
| 1486 | { | ||
| 1487 | /* Fill background with a stipple pattern. */ | ||
| 1488 | android_set_fill_style (s->gc, ANDROID_FILL_OPAQUE_STIPPLED); | ||
| 1489 | android_fill_rectangle (FRAME_ANDROID_WINDOW (s->f), s->gc, x, | ||
| 1490 | y, w, h); | ||
| 1491 | android_set_fill_style (s->gc, ANDROID_FILL_SOLID); | ||
| 1492 | } | ||
| 1493 | else | ||
| 1494 | android_clear_glyph_string_rect (s, x, y, w, h); | ||
| 1495 | } | ||
| 1496 | |||
| 1497 | static void | ||
| 1498 | android_draw_image_relief (struct glyph_string *s) | ||
| 1499 | { | ||
| 1500 | int x1, y1, thick; | ||
| 1501 | bool raised_p, top_p, bot_p, left_p, right_p; | ||
| 1502 | int extra_x, extra_y; | ||
| 1503 | struct android_rectangle r; | ||
| 1504 | int x = s->x; | ||
| 1505 | int y = s->ybase - image_ascent (s->img, s->face, &s->slice); | ||
| 1506 | |||
| 1507 | /* If first glyph of S has a left box line, start drawing it to the | ||
| 1508 | right of that line. */ | ||
| 1509 | if (s->face->box != FACE_NO_BOX | ||
| 1510 | && s->first_glyph->left_box_line_p | ||
| 1511 | && s->slice.x == 0) | ||
| 1512 | x += max (s->face->box_vertical_line_width, 0); | ||
| 1513 | |||
| 1514 | /* If there is a margin around the image, adjust x- and y-position | ||
| 1515 | by that margin. */ | ||
| 1516 | if (s->slice.x == 0) | ||
| 1517 | x += s->img->hmargin; | ||
| 1518 | if (s->slice.y == 0) | ||
| 1519 | y += s->img->vmargin; | ||
| 1520 | |||
| 1521 | if (s->hl == DRAW_IMAGE_SUNKEN | ||
| 1522 | || s->hl == DRAW_IMAGE_RAISED) | ||
| 1523 | { | ||
| 1524 | if (s->face->id == TAB_BAR_FACE_ID) | ||
| 1525 | thick = (tab_bar_button_relief < 0 | ||
| 1526 | ? DEFAULT_TAB_BAR_BUTTON_RELIEF | ||
| 1527 | : min (tab_bar_button_relief, 1000000)); | ||
| 1528 | else | ||
| 1529 | thick = (tool_bar_button_relief < 0 | ||
| 1530 | ? DEFAULT_TOOL_BAR_BUTTON_RELIEF | ||
| 1531 | : min (tool_bar_button_relief, 1000000)); | ||
| 1532 | raised_p = s->hl == DRAW_IMAGE_RAISED; | ||
| 1533 | } | ||
| 1534 | else | ||
| 1535 | { | ||
| 1536 | thick = eabs (s->img->relief); | ||
| 1537 | raised_p = s->img->relief > 0; | ||
| 1538 | } | ||
| 1539 | |||
| 1540 | x1 = x + s->slice.width - 1; | ||
| 1541 | y1 = y + s->slice.height - 1; | ||
| 1542 | |||
| 1543 | extra_x = extra_y = 0; | ||
| 1544 | if (s->face->id == TAB_BAR_FACE_ID) | ||
| 1545 | { | ||
| 1546 | if (CONSP (Vtab_bar_button_margin) | ||
| 1547 | && FIXNUMP (XCAR (Vtab_bar_button_margin)) | ||
| 1548 | && FIXNUMP (XCDR (Vtab_bar_button_margin))) | ||
| 1549 | { | ||
| 1550 | extra_x = XFIXNUM (XCAR (Vtab_bar_button_margin)) - thick; | ||
| 1551 | extra_y = XFIXNUM (XCDR (Vtab_bar_button_margin)) - thick; | ||
| 1552 | } | ||
| 1553 | else if (FIXNUMP (Vtab_bar_button_margin)) | ||
| 1554 | extra_x = extra_y = XFIXNUM (Vtab_bar_button_margin) - thick; | ||
| 1555 | } | ||
| 1556 | |||
| 1557 | if (s->face->id == TOOL_BAR_FACE_ID) | ||
| 1558 | { | ||
| 1559 | if (CONSP (Vtool_bar_button_margin) | ||
| 1560 | && FIXNUMP (XCAR (Vtool_bar_button_margin)) | ||
| 1561 | && FIXNUMP (XCDR (Vtool_bar_button_margin))) | ||
| 1562 | { | ||
| 1563 | extra_x = XFIXNUM (XCAR (Vtool_bar_button_margin)); | ||
| 1564 | extra_y = XFIXNUM (XCDR (Vtool_bar_button_margin)); | ||
| 1565 | } | ||
| 1566 | else if (FIXNUMP (Vtool_bar_button_margin)) | ||
| 1567 | extra_x = extra_y = XFIXNUM (Vtool_bar_button_margin); | ||
| 1568 | } | ||
| 1569 | |||
| 1570 | top_p = bot_p = left_p = right_p = false; | ||
| 1571 | |||
| 1572 | if (s->slice.x == 0) | ||
| 1573 | x -= thick + extra_x, left_p = true; | ||
| 1574 | if (s->slice.y == 0) | ||
| 1575 | y -= thick + extra_y, top_p = true; | ||
| 1576 | if (s->slice.x + s->slice.width == s->img->width) | ||
| 1577 | x1 += thick + extra_x, right_p = true; | ||
| 1578 | if (s->slice.y + s->slice.height == s->img->height) | ||
| 1579 | y1 += thick + extra_y, bot_p = true; | ||
| 1580 | |||
| 1581 | android_setup_relief_colors (s); | ||
| 1582 | get_glyph_string_clip_rect (s, &r); | ||
| 1583 | android_draw_relief_rect (s->f, x, y, x1, y1, thick, thick, raised_p, | ||
| 1584 | top_p, bot_p, left_p, right_p, &r); | ||
| 1585 | } | ||
| 1586 | |||
| 1587 | static void | ||
| 1588 | android_draw_image_foreground (struct glyph_string *s) | ||
| 1589 | { | ||
| 1590 | int x = s->x; | ||
| 1591 | int y = s->ybase - image_ascent (s->img, s->face, &s->slice); | ||
| 1592 | |||
| 1593 | /* If first glyph of S has a left box line, start drawing it to the | ||
| 1594 | right of that line. */ | ||
| 1595 | if (s->face->box != FACE_NO_BOX | ||
| 1596 | && s->first_glyph->left_box_line_p | ||
| 1597 | && s->slice.x == 0) | ||
| 1598 | x += max (s->face->box_vertical_line_width, 0); | ||
| 1599 | |||
| 1600 | /* If there is a margin around the image, adjust x- and y-position | ||
| 1601 | by that margin. */ | ||
| 1602 | if (s->slice.x == 0) | ||
| 1603 | x += s->img->hmargin; | ||
| 1604 | if (s->slice.y == 0) | ||
| 1605 | y += s->img->vmargin; | ||
| 1606 | |||
| 1607 | if (s->img->pixmap) | ||
| 1608 | { | ||
| 1609 | if (s->img->mask) | ||
| 1610 | { | ||
| 1611 | unsigned long mask = (ANDROID_GC_CLIP_MASK | ||
| 1612 | | ANDROID_GC_CLIP_X_ORIGIN | ||
| 1613 | | ANDROID_GC_CLIP_Y_ORIGIN | ||
| 1614 | | ANDROID_GC_FUNCTION); | ||
| 1615 | struct android_gc_values xgcv; | ||
| 1616 | struct android_rectangle clip_rect, image_rect, r; | ||
| 1617 | |||
| 1618 | xgcv.clip_mask = s->img->mask; | ||
| 1619 | xgcv.clip_x_origin = x - s->slice.x; | ||
| 1620 | xgcv.clip_y_origin = y - s->slice.y; | ||
| 1621 | xgcv.function = ANDROID_GC_COPY; | ||
| 1622 | android_change_gc (s->gc, mask, &xgcv); | ||
| 1623 | |||
| 1624 | get_glyph_string_clip_rect (s, &clip_rect); | ||
| 1625 | image_rect.x = x; | ||
| 1626 | image_rect.y = y; | ||
| 1627 | image_rect.width = s->slice.width; | ||
| 1628 | image_rect.height = s->slice.height; | ||
| 1629 | |||
| 1630 | if (gui_intersect_rectangles (&clip_rect, &image_rect, &r)) | ||
| 1631 | android_copy_area (s->img->pixmap, FRAME_ANDROID_WINDOW (s->f), | ||
| 1632 | s->gc, s->slice.x + r.x - x, | ||
| 1633 | s->slice.y + r.y - y, | ||
| 1634 | r.x, r.y, r.width, r.height); | ||
| 1635 | } | ||
| 1636 | else | ||
| 1637 | { | ||
| 1638 | unsigned long mask = (ANDROID_GC_CLIP_MASK | ||
| 1639 | | ANDROID_GC_CLIP_X_ORIGIN | ||
| 1640 | | ANDROID_GC_CLIP_Y_ORIGIN | ||
| 1641 | | ANDROID_GC_FUNCTION); | ||
| 1642 | struct android_gc_values xgcv; | ||
| 1643 | struct android_rectangle clip_rect, image_rect, r; | ||
| 1644 | |||
| 1645 | xgcv.clip_mask = s->img->mask; | ||
| 1646 | xgcv.clip_x_origin = x - s->slice.x; | ||
| 1647 | xgcv.clip_y_origin = y - s->slice.y; | ||
| 1648 | xgcv.function = ANDROID_GC_COPY; | ||
| 1649 | android_change_gc (s->gc, mask, &xgcv); | ||
| 1650 | |||
| 1651 | get_glyph_string_clip_rect (s, &clip_rect); | ||
| 1652 | image_rect.x = x; | ||
| 1653 | image_rect.y = y; | ||
| 1654 | image_rect.width = s->slice.width; | ||
| 1655 | image_rect.height = s->slice.height; | ||
| 1656 | |||
| 1657 | if (gui_intersect_rectangles (&clip_rect, &image_rect, &r)) | ||
| 1658 | android_copy_area (s->img->pixmap, | ||
| 1659 | FRAME_ANDROID_WINDOW (s->f), | ||
| 1660 | s->gc, s->slice.x + r.x - x, | ||
| 1661 | s->slice.y + r.y - y, | ||
| 1662 | r.x, r.y, r.width, r.height); | ||
| 1663 | |||
| 1664 | /* When the image has a mask, we can expect that at | ||
| 1665 | least part of a mouse highlight or a block cursor will | ||
| 1666 | be visible. If the image doesn't have a mask, make | ||
| 1667 | a block cursor visible by drawing a rectangle around | ||
| 1668 | the image. I believe it's looking better if we do | ||
| 1669 | nothing here for mouse-face. */ | ||
| 1670 | if (s->hl == DRAW_CURSOR) | ||
| 1671 | { | ||
| 1672 | int relief = eabs (s->img->relief); | ||
| 1673 | android_draw_rectangle (FRAME_ANDROID_WINDOW (s->f), s->gc, | ||
| 1674 | x - relief, y - relief, | ||
| 1675 | s->slice.width + relief*2 - 1, | ||
| 1676 | s->slice.height + relief*2 - 1); | ||
| 1677 | } | ||
| 1678 | } | ||
| 1679 | } | ||
| 1680 | else | ||
| 1681 | /* Draw a rectangle if image could not be loaded. */ | ||
| 1682 | android_draw_rectangle (FRAME_ANDROID_WINDOW (s->f), s->gc, x, y, | ||
| 1683 | s->slice.width - 1, s->slice.height - 1); | ||
| 1684 | } | ||
| 1685 | |||
| 1686 | /* Draw the foreground of image glyph string S to PIXMAP. */ | ||
| 1687 | |||
| 1688 | static void | ||
| 1689 | android_draw_image_foreground_1 (struct glyph_string *s, | ||
| 1690 | android_pixmap pixmap) | ||
| 1691 | { | ||
| 1692 | int x = 0; | ||
| 1693 | int y = s->ybase - s->y - image_ascent (s->img, s->face, &s->slice); | ||
| 1694 | |||
| 1695 | /* If first glyph of S has a left box line, start drawing it to the | ||
| 1696 | right of that line. */ | ||
| 1697 | if (s->face->box != FACE_NO_BOX | ||
| 1698 | && s->first_glyph->left_box_line_p | ||
| 1699 | && s->slice.x == 0) | ||
| 1700 | x += max (s->face->box_vertical_line_width, 0); | ||
| 1701 | |||
| 1702 | /* If there is a margin around the image, adjust x- and y-position | ||
| 1703 | by that margin. */ | ||
| 1704 | if (s->slice.x == 0) | ||
| 1705 | x += s->img->hmargin; | ||
| 1706 | if (s->slice.y == 0) | ||
| 1707 | y += s->img->vmargin; | ||
| 1708 | |||
| 1709 | if (s->img->pixmap) | ||
| 1710 | { | ||
| 1711 | if (s->img->mask) | ||
| 1712 | { | ||
| 1713 | unsigned long mask = (ANDROID_GC_CLIP_MASK | ||
| 1714 | | ANDROID_GC_CLIP_X_ORIGIN | ||
| 1715 | | ANDROID_GC_CLIP_Y_ORIGIN | ||
| 1716 | | ANDROID_GC_FUNCTION); | ||
| 1717 | struct android_gc_values xgcv; | ||
| 1718 | struct android_rectangle clip_rect, image_rect, r; | ||
| 1719 | |||
| 1720 | xgcv.clip_mask = s->img->mask; | ||
| 1721 | xgcv.clip_x_origin = x - s->slice.x; | ||
| 1722 | xgcv.clip_y_origin = y - s->slice.y; | ||
| 1723 | xgcv.function = ANDROID_GC_COPY; | ||
| 1724 | android_change_gc (s->gc, mask, &xgcv); | ||
| 1725 | |||
| 1726 | get_glyph_string_clip_rect (s, &clip_rect); | ||
| 1727 | image_rect.x = x; | ||
| 1728 | image_rect.y = y; | ||
| 1729 | image_rect.width = s->slice.width; | ||
| 1730 | image_rect.height = s->slice.height; | ||
| 1731 | |||
| 1732 | if (gui_intersect_rectangles (&clip_rect, &image_rect, &r)) | ||
| 1733 | android_copy_area (s->img->pixmap, pixmap, s->gc, | ||
| 1734 | s->slice.x + r.x - x, | ||
| 1735 | s->slice.y + r.y - y, | ||
| 1736 | r.x, r.y, r.width, r.height); | ||
| 1737 | |||
| 1738 | android_set_clip_mask (s->gc, ANDROID_NONE); | ||
| 1739 | } | ||
| 1740 | else | ||
| 1741 | { | ||
| 1742 | android_copy_area (s->img->pixmap, pixmap, s->gc, | ||
| 1743 | s->slice.x, s->slice.y, | ||
| 1744 | s->slice.width, s->slice.height, x, y); | ||
| 1745 | |||
| 1746 | /* When the image has a mask, we can expect that at | ||
| 1747 | least part of a mouse highlight or a block cursor will | ||
| 1748 | be visible. If the image doesn't have a mask, make | ||
| 1749 | a block cursor visible by drawing a rectangle around | ||
| 1750 | the image. I believe it's looking better if we do | ||
| 1751 | nothing here for mouse-face. */ | ||
| 1752 | if (s->hl == DRAW_CURSOR) | ||
| 1753 | { | ||
| 1754 | int r = eabs (s->img->relief); | ||
| 1755 | android_draw_rectangle (FRAME_ANDROID_WINDOW (s->f), | ||
| 1756 | s->gc, x - r, y - r, | ||
| 1757 | s->slice.width + r*2 - 1, | ||
| 1758 | s->slice.height + r*2 - 1); | ||
| 1759 | } | ||
| 1760 | } | ||
| 1761 | } | ||
| 1762 | else | ||
| 1763 | /* Draw a rectangle if image could not be loaded. */ | ||
| 1764 | android_draw_rectangle (FRAME_ANDROID_WINDOW (s->f), s->gc, x, y, | ||
| 1765 | s->slice.width - 1, s->slice.height - 1); | ||
| 1766 | } | ||
| 1767 | |||
| 1768 | static void | ||
| 1769 | android_draw_image_glyph_string (struct glyph_string *s) | ||
| 1770 | { | ||
| 1771 | int box_line_hwidth = max (s->face->box_vertical_line_width, 0); | ||
| 1772 | int box_line_vwidth = max (s->face->box_horizontal_line_width, 0); | ||
| 1773 | int height; | ||
| 1774 | android_pixmap pixmap = ANDROID_NONE; | ||
| 1775 | |||
| 1776 | height = s->height; | ||
| 1777 | if (s->slice.y == 0) | ||
| 1778 | height -= box_line_vwidth; | ||
| 1779 | if (s->slice.y + s->slice.height >= s->img->height) | ||
| 1780 | height -= box_line_vwidth; | ||
| 1781 | |||
| 1782 | /* Fill background with face under the image. Do it only if row is | ||
| 1783 | taller than image or if image has a clip mask to reduce | ||
| 1784 | flickering. */ | ||
| 1785 | s->stippled_p = s->face->stipple != 0; | ||
| 1786 | if (height > s->slice.height | ||
| 1787 | || s->img->hmargin | ||
| 1788 | || s->img->vmargin | ||
| 1789 | || s->img->mask | ||
| 1790 | || s->img->pixmap == 0 | ||
| 1791 | || s->width != s->background_width) | ||
| 1792 | { | ||
| 1793 | if (s->stippled_p) | ||
| 1794 | s->row->stipple_p = true; | ||
| 1795 | |||
| 1796 | if (s->img->mask) | ||
| 1797 | { | ||
| 1798 | /* Create a pixmap as large as the glyph string. Fill it | ||
| 1799 | with the background color. Copy the image to it, using | ||
| 1800 | its mask. Copy the temporary pixmap to the display. */ | ||
| 1801 | int depth = FRAME_DISPLAY_INFO (s->f)->n_planes; | ||
| 1802 | |||
| 1803 | /* Create a pixmap as large as the glyph string. */ | ||
| 1804 | pixmap = android_create_pixmap (s->background_width, | ||
| 1805 | s->height, depth); | ||
| 1806 | |||
| 1807 | /* Don't clip in the following because we're working on the | ||
| 1808 | pixmap. */ | ||
| 1809 | android_set_clip_mask (s->gc, ANDROID_NONE); | ||
| 1810 | |||
| 1811 | /* Fill the pixmap with the background color/stipple. */ | ||
| 1812 | if (s->stippled_p) | ||
| 1813 | { | ||
| 1814 | /* Fill background with a stipple pattern. */ | ||
| 1815 | android_set_fill_style (s->gc, ANDROID_FILL_OPAQUE_STIPPLED); | ||
| 1816 | android_set_ts_origin (s->gc, - s->x, - s->y); | ||
| 1817 | android_fill_rectangle (pixmap, s->gc, | ||
| 1818 | 0, 0, s->background_width, s->height); | ||
| 1819 | android_set_fill_style (s->gc, ANDROID_FILL_OPAQUE_STIPPLED); | ||
| 1820 | android_set_ts_origin (s->gc, 0, 0); | ||
| 1821 | } | ||
| 1822 | else | ||
| 1823 | { | ||
| 1824 | struct android_gc_values xgcv; | ||
| 1825 | |||
| 1826 | android_get_gc_values (s->gc, (ANDROID_GC_FOREGROUND | ||
| 1827 | | ANDROID_GC_BACKGROUND), | ||
| 1828 | &xgcv); | ||
| 1829 | android_set_foreground (s->gc, xgcv.background); | ||
| 1830 | android_fill_rectangle (pixmap, s->gc, | ||
| 1831 | 0, 0, s->background_width, s->height); | ||
| 1832 | android_set_background (s->gc, xgcv.foreground); | ||
| 1833 | } | ||
| 1834 | } | ||
| 1835 | else | ||
| 1836 | { | ||
| 1837 | int x = s->x; | ||
| 1838 | int y = s->y; | ||
| 1839 | int width = s->background_width; | ||
| 1840 | |||
| 1841 | if (s->first_glyph->left_box_line_p | ||
| 1842 | && s->slice.x == 0) | ||
| 1843 | { | ||
| 1844 | x += box_line_hwidth; | ||
| 1845 | width -= box_line_hwidth; | ||
| 1846 | } | ||
| 1847 | |||
| 1848 | if (s->slice.y == 0) | ||
| 1849 | y += box_line_vwidth; | ||
| 1850 | |||
| 1851 | android_draw_glyph_string_bg_rect (s, x, y, width, height); | ||
| 1852 | } | ||
| 1853 | |||
| 1854 | s->background_filled_p = true; | ||
| 1855 | } | ||
| 1856 | |||
| 1857 | /* Draw the foreground. */ | ||
| 1858 | if (pixmap != ANDROID_NONE) | ||
| 1859 | { | ||
| 1860 | android_draw_image_foreground_1 (s, pixmap); | ||
| 1861 | android_set_glyph_string_clipping (s); | ||
| 1862 | android_copy_area (pixmap, FRAME_ANDROID_WINDOW (s->f), s->gc, | ||
| 1863 | 0, 0, s->background_width, s->height, s->x, | ||
| 1864 | s->y); | ||
| 1865 | android_free_pixmap (pixmap); | ||
| 1866 | } | ||
| 1867 | else | ||
| 1868 | android_draw_image_foreground (s); | ||
| 1869 | |||
| 1870 | /* If we must draw a relief around the image, do it. */ | ||
| 1871 | if (s->img->relief | ||
| 1872 | || s->hl == DRAW_IMAGE_RAISED | ||
| 1873 | || s->hl == DRAW_IMAGE_SUNKEN) | ||
| 1874 | android_draw_image_relief (s); | ||
| 1875 | } | ||
| 1876 | |||
| 1877 | static void | ||
| 1878 | android_draw_stretch_glyph_string (struct glyph_string *s) | ||
| 1879 | { | ||
| 1880 | eassert (s->first_glyph->type == STRETCH_GLYPH); | ||
| 1881 | |||
| 1882 | if (s->hl == DRAW_CURSOR && !x_stretch_cursor_p) | ||
| 1883 | { | ||
| 1884 | /* If `x-stretch-cursor' is nil, don't draw a block cursor as | ||
| 1885 | wide as the stretch glyph. */ | ||
| 1886 | int width, background_width = s->background_width; | ||
| 1887 | int x = s->x; | ||
| 1888 | |||
| 1889 | if (!s->row->reversed_p) | ||
| 1890 | { | ||
| 1891 | int left_x = window_box_left_offset (s->w, TEXT_AREA); | ||
| 1892 | |||
| 1893 | if (x < left_x) | ||
| 1894 | { | ||
| 1895 | background_width -= left_x - x; | ||
| 1896 | x = left_x; | ||
| 1897 | } | ||
| 1898 | } | ||
| 1899 | else | ||
| 1900 | { | ||
| 1901 | /* In R2L rows, draw the cursor on the right edge of the | ||
| 1902 | stretch glyph. */ | ||
| 1903 | int right_x = window_box_right (s->w, TEXT_AREA); | ||
| 1904 | |||
| 1905 | if (x + background_width > right_x) | ||
| 1906 | background_width -= x - right_x; | ||
| 1907 | x += background_width; | ||
| 1908 | } | ||
| 1909 | width = min (FRAME_COLUMN_WIDTH (s->f), background_width); | ||
| 1910 | if (s->row->reversed_p) | ||
| 1911 | x -= width; | ||
| 1912 | |||
| 1913 | /* Draw cursor. */ | ||
| 1914 | android_draw_glyph_string_bg_rect (s, x, s->y, width, s->height); | ||
| 1915 | |||
| 1916 | /* Clear rest using the GC of the original non-cursor face. */ | ||
| 1917 | if (width < background_width) | ||
| 1918 | { | ||
| 1919 | int y = s->y; | ||
| 1920 | int w = background_width - width, h = s->height; | ||
| 1921 | struct android_rectangle r; | ||
| 1922 | struct android_gc *gc; | ||
| 1923 | |||
| 1924 | if (!s->row->reversed_p) | ||
| 1925 | x += width; | ||
| 1926 | else | ||
| 1927 | x = s->x; | ||
| 1928 | if (s->row->mouse_face_p | ||
| 1929 | && cursor_in_mouse_face_p (s->w)) | ||
| 1930 | { | ||
| 1931 | android_set_mouse_face_gc (s); | ||
| 1932 | gc = s->gc; | ||
| 1933 | } | ||
| 1934 | else | ||
| 1935 | gc = s->face->gc; | ||
| 1936 | |||
| 1937 | get_glyph_string_clip_rect (s, &r); | ||
| 1938 | android_set_clip_rectangles (gc, 0, 0, &r, 1); | ||
| 1939 | |||
| 1940 | if (s->face->stipple) | ||
| 1941 | { | ||
| 1942 | /* Fill background with a stipple pattern. */ | ||
| 1943 | android_set_fill_style (gc, ANDROID_FILL_OPAQUE_STIPPLED); | ||
| 1944 | android_fill_rectangle (FRAME_ANDROID_WINDOW (s->f), | ||
| 1945 | gc, x, y, w, h); | ||
| 1946 | android_set_fill_style (gc, ANDROID_FILL_SOLID); | ||
| 1947 | |||
| 1948 | s->row->stipple_p = true; | ||
| 1949 | } | ||
| 1950 | else | ||
| 1951 | { | ||
| 1952 | struct android_gc_values xgcv; | ||
| 1953 | android_get_gc_values (gc, (ANDROID_GC_FOREGROUND | ||
| 1954 | | ANDROID_GC_BACKGROUND), | ||
| 1955 | &xgcv); | ||
| 1956 | android_set_foreground (gc, xgcv.background); | ||
| 1957 | android_fill_rectangle (FRAME_ANDROID_WINDOW (s->f), | ||
| 1958 | gc, x, y, w, h); | ||
| 1959 | android_set_foreground (gc, xgcv.foreground); | ||
| 1960 | } | ||
| 1961 | |||
| 1962 | android_reset_clip_rectangles (s->f, gc); | ||
| 1963 | } | ||
| 1964 | } | ||
| 1965 | else if (!s->background_filled_p) | ||
| 1966 | { | ||
| 1967 | int background_width = s->background_width; | ||
| 1968 | int x = s->x, text_left_x = window_box_left (s->w, TEXT_AREA); | ||
| 1969 | |||
| 1970 | /* Don't draw into left fringe or scrollbar area except for | ||
| 1971 | header line and mode line. */ | ||
| 1972 | if (s->area == TEXT_AREA | ||
| 1973 | && x < text_left_x && !s->row->mode_line_p) | ||
| 1974 | { | ||
| 1975 | background_width -= text_left_x - x; | ||
| 1976 | x = text_left_x; | ||
| 1977 | } | ||
| 1978 | |||
| 1979 | if (!s->row->stipple_p) | ||
| 1980 | s->row->stipple_p = s->stippled_p; | ||
| 1981 | |||
| 1982 | if (background_width > 0) | ||
| 1983 | android_draw_glyph_string_bg_rect (s, x, s->y, | ||
| 1984 | background_width, | ||
| 1985 | s->height); | ||
| 1986 | } | ||
| 1987 | |||
| 1988 | s->background_filled_p = true; | ||
| 1989 | } | ||
| 1990 | |||
| 1991 | static void | ||
| 1992 | android_draw_underwave (struct glyph_string *s, int decoration_width) | ||
| 1993 | { | ||
| 1994 | int wave_height = 3, wave_length = 2; | ||
| 1995 | int dx, dy, x0, y0, width, x1, y1, x2, y2, xmax; | ||
| 1996 | bool odd; | ||
| 1997 | struct android_rectangle wave_clip, string_clip, final_clip; | ||
| 1998 | |||
| 1999 | dx = wave_length; | ||
| 2000 | dy = wave_height - 1; | ||
| 2001 | x0 = s->x; | ||
| 2002 | y0 = s->ybase + wave_height / 2; | ||
| 2003 | width = decoration_width; | ||
| 2004 | xmax = x0 + width; | ||
| 2005 | |||
| 2006 | /* Find and set clipping rectangle */ | ||
| 2007 | |||
| 2008 | wave_clip.x = x0; | ||
| 2009 | wave_clip.y = y0; | ||
| 2010 | wave_clip.width = width; | ||
| 2011 | wave_clip.height = wave_height; | ||
| 2012 | get_glyph_string_clip_rect (s, &string_clip); | ||
| 2013 | |||
| 2014 | if (!gui_intersect_rectangles (&wave_clip, &string_clip, &final_clip)) | ||
| 2015 | return; | ||
| 2016 | |||
| 2017 | android_set_clip_rectangles (s->gc, 0, 0, &final_clip, 1); | ||
| 2018 | |||
| 2019 | /* Draw the waves */ | ||
| 2020 | |||
| 2021 | x1 = x0 - (x0 % dx); | ||
| 2022 | x2 = x1 + dx; | ||
| 2023 | odd = (x1 / dx) & 1; | ||
| 2024 | y1 = y2 = y0; | ||
| 2025 | |||
| 2026 | if (odd) | ||
| 2027 | y1 += dy; | ||
| 2028 | else | ||
| 2029 | y2 += dy; | ||
| 2030 | |||
| 2031 | if (INT_MAX - dx < xmax) | ||
| 2032 | emacs_abort (); | ||
| 2033 | |||
| 2034 | while (x1 <= xmax) | ||
| 2035 | { | ||
| 2036 | android_draw_line (FRAME_ANDROID_WINDOW (s->f), s->gc, | ||
| 2037 | x1, y1, x2, y2); | ||
| 2038 | x1 = x2, y1 = y2; | ||
| 2039 | x2 += dx, y2 = y0 + odd*dy; | ||
| 2040 | odd = !odd; | ||
| 2041 | } | ||
| 2042 | |||
| 2043 | /* Restore previous clipping rectangle(s) */ | ||
| 2044 | android_set_clip_rectangles (s->gc, 0, 0, s->clip, s->num_clips); | ||
| 2045 | } | ||
| 2046 | |||
| 2047 | static void | ||
| 2048 | android_draw_glyph_string_foreground (struct glyph_string *s) | ||
| 2049 | { | ||
| 2050 | int i, x; | ||
| 2051 | |||
| 2052 | /* If first glyph of S has a left box line, start drawing the text | ||
| 2053 | of S to the right of that box line. */ | ||
| 2054 | if (s->face->box != FACE_NO_BOX | ||
| 2055 | && s->first_glyph->left_box_line_p) | ||
| 2056 | x = s->x + max (s->face->box_vertical_line_width, 0); | ||
| 2057 | else | ||
| 2058 | x = s->x; | ||
| 2059 | |||
| 2060 | /* Draw characters of S as rectangles if S's font could not be | ||
| 2061 | loaded. */ | ||
| 2062 | if (s->font_not_found_p) | ||
| 2063 | { | ||
| 2064 | for (i = 0; i < s->nchars; ++i) | ||
| 2065 | { | ||
| 2066 | struct glyph *g = s->first_glyph + i; | ||
| 2067 | android_draw_rectangle (FRAME_ANDROID_WINDOW (s->f), | ||
| 2068 | s->gc, x, s->y, | ||
| 2069 | g->pixel_width - 1, | ||
| 2070 | s->height - 1); | ||
| 2071 | x += g->pixel_width; | ||
| 2072 | } | ||
| 2073 | } | ||
| 2074 | else | ||
| 2075 | { | ||
| 2076 | struct font *font = s->font; | ||
| 2077 | int boff = font->baseline_offset; | ||
| 2078 | int y; | ||
| 2079 | |||
| 2080 | if (font->vertical_centering) | ||
| 2081 | boff = VCENTER_BASELINE_OFFSET (font, s->f) - boff; | ||
| 2082 | |||
| 2083 | y = s->ybase - boff; | ||
| 2084 | if (s->for_overlaps | ||
| 2085 | || (s->background_filled_p && s->hl != DRAW_CURSOR)) | ||
| 2086 | font->driver->draw (s, 0, s->nchars, x, y, false); | ||
| 2087 | else | ||
| 2088 | font->driver->draw (s, 0, s->nchars, x, y, true); | ||
| 2089 | if (s->face->overstrike) | ||
| 2090 | font->driver->draw (s, 0, s->nchars, x + 1, y, false); | ||
| 2091 | } | ||
| 2092 | } | ||
| 2093 | |||
| 2094 | static void | ||
| 2095 | android_draw_composite_glyph_string_foreground (struct glyph_string *s) | ||
| 2096 | { | ||
| 2097 | int i, j, x; | ||
| 2098 | struct font *font = s->font; | ||
| 2099 | |||
| 2100 | /* If first glyph of S has a left box line, start drawing the text | ||
| 2101 | of S to the right of that box line. */ | ||
| 2102 | if (s->face && s->face->box != FACE_NO_BOX | ||
| 2103 | && s->first_glyph->left_box_line_p) | ||
| 2104 | x = s->x + max (s->face->box_vertical_line_width, 0); | ||
| 2105 | else | ||
| 2106 | x = s->x; | ||
| 2107 | |||
| 2108 | /* S is a glyph string for a composition. S->cmp_from is the index | ||
| 2109 | of the first character drawn for glyphs of this composition. | ||
| 2110 | S->cmp_from == 0 means we are drawing the very first character of | ||
| 2111 | this composition. */ | ||
| 2112 | |||
| 2113 | /* Draw a rectangle for the composition if the font for the very | ||
| 2114 | first character of the composition could not be loaded. */ | ||
| 2115 | if (s->font_not_found_p) | ||
| 2116 | { | ||
| 2117 | if (s->cmp_from == 0) | ||
| 2118 | android_draw_rectangle (FRAME_ANDROID_WINDOW (s->f), | ||
| 2119 | s->gc, x, s->y, | ||
| 2120 | s->width - 1, s->height - 1); | ||
| 2121 | } | ||
| 2122 | else if (! s->first_glyph->u.cmp.automatic) | ||
| 2123 | { | ||
| 2124 | int y = s->ybase; | ||
| 2125 | |||
| 2126 | for (i = 0, j = s->cmp_from; i < s->nchars; i++, j++) | ||
| 2127 | /* TAB in a composition means display glyphs with | ||
| 2128 | padding space on the left or right. */ | ||
| 2129 | if (COMPOSITION_GLYPH (s->cmp, j) != '\t') | ||
| 2130 | { | ||
| 2131 | int xx = x + s->cmp->offsets[j * 2]; | ||
| 2132 | int yy = y - s->cmp->offsets[j * 2 + 1]; | ||
| 2133 | |||
| 2134 | font->driver->draw (s, j, j + 1, xx, yy, false); | ||
| 2135 | if (s->face->overstrike) | ||
| 2136 | font->driver->draw (s, j, j + 1, xx + 1, yy, false); | ||
| 2137 | } | ||
| 2138 | } | ||
| 2139 | else | ||
| 2140 | { | ||
| 2141 | Lisp_Object gstring = composition_gstring_from_id (s->cmp_id); | ||
| 2142 | Lisp_Object glyph; | ||
| 2143 | int y = s->ybase; | ||
| 2144 | int width = 0; | ||
| 2145 | |||
| 2146 | for (i = j = s->cmp_from; i < s->cmp_to; i++) | ||
| 2147 | { | ||
| 2148 | glyph = LGSTRING_GLYPH (gstring, i); | ||
| 2149 | if (NILP (LGLYPH_ADJUSTMENT (glyph))) | ||
| 2150 | width += LGLYPH_WIDTH (glyph); | ||
| 2151 | else | ||
| 2152 | { | ||
| 2153 | int xoff, yoff, wadjust; | ||
| 2154 | |||
| 2155 | if (j < i) | ||
| 2156 | { | ||
| 2157 | font->driver->draw (s, j, i, x, y, false); | ||
| 2158 | if (s->face->overstrike) | ||
| 2159 | font->driver->draw (s, j, i, x + 1, y, false); | ||
| 2160 | x += width; | ||
| 2161 | } | ||
| 2162 | xoff = LGLYPH_XOFF (glyph); | ||
| 2163 | yoff = LGLYPH_YOFF (glyph); | ||
| 2164 | wadjust = LGLYPH_WADJUST (glyph); | ||
| 2165 | font->driver->draw (s, i, i + 1, x + xoff, y + yoff, false); | ||
| 2166 | if (s->face->overstrike) | ||
| 2167 | font->driver->draw (s, i, i + 1, x + xoff + 1, y + yoff, | ||
| 2168 | false); | ||
| 2169 | x += wadjust; | ||
| 2170 | j = i + 1; | ||
| 2171 | width = 0; | ||
| 2172 | } | ||
| 2173 | } | ||
| 2174 | if (j < i) | ||
| 2175 | { | ||
| 2176 | font->driver->draw (s, j, i, x, y, false); | ||
| 2177 | if (s->face->overstrike) | ||
| 2178 | font->driver->draw (s, j, i, x + 1, y, false); | ||
| 2179 | } | ||
| 2180 | } | ||
| 2181 | } | ||
| 2182 | |||
| 2183 | static void | ||
| 2184 | android_draw_glyphless_glyph_string_foreground (struct glyph_string *s) | ||
| 2185 | { | ||
| 2186 | struct glyph *glyph = s->first_glyph; | ||
| 2187 | unsigned char2b[8]; | ||
| 2188 | int x, i, j; | ||
| 2189 | |||
| 2190 | /* If first glyph of S has a left box line, start drawing the text | ||
| 2191 | of S to the right of that box line. */ | ||
| 2192 | if (s->face && s->face->box != FACE_NO_BOX | ||
| 2193 | && s->first_glyph->left_box_line_p) | ||
| 2194 | x = s->x + max (s->face->box_vertical_line_width, 0); | ||
| 2195 | else | ||
| 2196 | x = s->x; | ||
| 2197 | |||
| 2198 | s->char2b = char2b; | ||
| 2199 | |||
| 2200 | for (i = 0; i < s->nchars; i++, glyph++) | ||
| 2201 | { | ||
| 2202 | #ifdef GCC_LINT | ||
| 2203 | enum { PACIFY_GCC_BUG_81401 = 1 }; | ||
| 2204 | #else | ||
| 2205 | enum { PACIFY_GCC_BUG_81401 = 0 }; | ||
| 2206 | #endif | ||
| 2207 | char buf[7 + PACIFY_GCC_BUG_81401]; | ||
| 2208 | char *str = NULL; | ||
| 2209 | int len = glyph->u.glyphless.len; | ||
| 2210 | |||
| 2211 | if (glyph->u.glyphless.method == GLYPHLESS_DISPLAY_ACRONYM) | ||
| 2212 | { | ||
| 2213 | if (len > 0 | ||
| 2214 | && CHAR_TABLE_P (Vglyphless_char_display) | ||
| 2215 | && (CHAR_TABLE_EXTRA_SLOTS (XCHAR_TABLE (Vglyphless_char_display)) | ||
| 2216 | >= 1)) | ||
| 2217 | { | ||
| 2218 | Lisp_Object acronym | ||
| 2219 | = (! glyph->u.glyphless.for_no_font | ||
| 2220 | ? CHAR_TABLE_REF (Vglyphless_char_display, | ||
| 2221 | glyph->u.glyphless.ch) | ||
| 2222 | : XCHAR_TABLE (Vglyphless_char_display)->extras[0]); | ||
| 2223 | if (CONSP (acronym)) | ||
| 2224 | acronym = XCAR (acronym); | ||
| 2225 | if (STRINGP (acronym)) | ||
| 2226 | str = SSDATA (acronym); | ||
| 2227 | } | ||
| 2228 | } | ||
| 2229 | else if (glyph->u.glyphless.method == GLYPHLESS_DISPLAY_HEX_CODE) | ||
| 2230 | { | ||
| 2231 | unsigned int ch = glyph->u.glyphless.ch; | ||
| 2232 | eassume (ch <= MAX_CHAR); | ||
| 2233 | sprintf (buf, "%0*X", ch < 0x10000 ? 4 : 6, ch); | ||
| 2234 | str = buf; | ||
| 2235 | } | ||
| 2236 | |||
| 2237 | if (str) | ||
| 2238 | { | ||
| 2239 | int upper_len = (len + 1) / 2; | ||
| 2240 | |||
| 2241 | /* It is assured that all LEN characters in STR is ASCII. */ | ||
| 2242 | for (j = 0; j < len; j++) | ||
| 2243 | char2b[j] = s->font->driver->encode_char (s->font, str[j]) & 0xFFFF; | ||
| 2244 | s->font->driver->draw (s, 0, upper_len, | ||
| 2245 | x + glyph->slice.glyphless.upper_xoff, | ||
| 2246 | s->ybase + glyph->slice.glyphless.upper_yoff, | ||
| 2247 | false); | ||
| 2248 | s->font->driver->draw (s, upper_len, len, | ||
| 2249 | x + glyph->slice.glyphless.lower_xoff, | ||
| 2250 | s->ybase + glyph->slice.glyphless.lower_yoff, | ||
| 2251 | false); | ||
| 2252 | } | ||
| 2253 | if (glyph->u.glyphless.method != GLYPHLESS_DISPLAY_THIN_SPACE) | ||
| 2254 | android_draw_rectangle (FRAME_ANDROID_WINDOW (s->f), s->gc, | ||
| 2255 | x, s->ybase - glyph->ascent, | ||
| 2256 | glyph->pixel_width - 1, | ||
| 2257 | glyph->ascent + glyph->descent - 1); | ||
| 2258 | x += glyph->pixel_width; | ||
| 2259 | } | ||
| 2260 | |||
| 2261 | /* Defend against hypothetical bad code elsewhere that uses | ||
| 2262 | s->char2b after this function returns. */ | ||
| 2263 | s->char2b = NULL; | ||
| 2264 | } | ||
| 2265 | |||
| 2266 | static void | ||
| 2267 | android_draw_glyph_string (struct glyph_string *s) | ||
| 2268 | { | ||
| 2269 | bool relief_drawn_p = false; | ||
| 2270 | |||
| 2271 | /* If S draws into the background of its successors, draw the | ||
| 2272 | background of the successors first so that S can draw into it. | ||
| 2273 | This makes S->next use XDrawString instead of XDrawImageString. */ | ||
| 2274 | if (s->next && s->right_overhang && !s->for_overlaps) | ||
| 2275 | { | ||
| 2276 | int width; | ||
| 2277 | struct glyph_string *next; | ||
| 2278 | |||
| 2279 | for (width = 0, next = s->next; | ||
| 2280 | next && width < s->right_overhang; | ||
| 2281 | width += next->width, next = next->next) | ||
| 2282 | if (next->first_glyph->type != IMAGE_GLYPH) | ||
| 2283 | { | ||
| 2284 | android_set_glyph_string_gc (next); | ||
| 2285 | android_set_glyph_string_clipping (next); | ||
| 2286 | if (next->first_glyph->type == STRETCH_GLYPH) | ||
| 2287 | android_draw_stretch_glyph_string (next); | ||
| 2288 | else | ||
| 2289 | android_draw_glyph_string_background (next, true); | ||
| 2290 | next->num_clips = 0; | ||
| 2291 | } | ||
| 2292 | } | ||
| 2293 | |||
| 2294 | /* Set up S->gc, set clipping and draw S. */ | ||
| 2295 | android_set_glyph_string_gc (s); | ||
| 2296 | |||
| 2297 | /* Draw relief (if any) in advance for char/composition so that the | ||
| 2298 | glyph string can be drawn over it. */ | ||
| 2299 | if (!s->for_overlaps | ||
| 2300 | && s->face->box != FACE_NO_BOX | ||
| 2301 | && (s->first_glyph->type == CHAR_GLYPH | ||
| 2302 | || s->first_glyph->type == COMPOSITE_GLYPH)) | ||
| 2303 | |||
| 2304 | { | ||
| 2305 | android_set_glyph_string_clipping (s); | ||
| 2306 | android_draw_glyph_string_background (s, true); | ||
| 2307 | android_draw_glyph_string_box (s); | ||
| 2308 | android_set_glyph_string_clipping (s); | ||
| 2309 | relief_drawn_p = true; | ||
| 2310 | } | ||
| 2311 | else if (!s->clip_head /* draw_glyphs didn't specify a clip mask. */ | ||
| 2312 | && !s->clip_tail | ||
| 2313 | && ((s->prev && s->prev->hl != s->hl && s->left_overhang) | ||
| 2314 | || (s->next && s->next->hl != s->hl && s->right_overhang))) | ||
| 2315 | /* We must clip just this glyph. left_overhang part has already | ||
| 2316 | drawn when s->prev was drawn, and right_overhang part will be | ||
| 2317 | drawn later when s->next is drawn. */ | ||
| 2318 | android_set_glyph_string_clipping_exactly (s, s); | ||
| 2319 | else | ||
| 2320 | android_set_glyph_string_clipping (s); | ||
| 2321 | |||
| 2322 | switch (s->first_glyph->type) | ||
| 2323 | { | ||
| 2324 | case IMAGE_GLYPH: | ||
| 2325 | android_draw_image_glyph_string (s); | ||
| 2326 | break; | ||
| 2327 | |||
| 2328 | case XWIDGET_GLYPH: | ||
| 2329 | emacs_abort (); | ||
| 2330 | break; | ||
| 2331 | |||
| 2332 | case STRETCH_GLYPH: | ||
| 2333 | android_draw_stretch_glyph_string (s); | ||
| 2334 | break; | ||
| 2335 | |||
| 2336 | case CHAR_GLYPH: | ||
| 2337 | if (s->for_overlaps) | ||
| 2338 | s->background_filled_p = true; | ||
| 2339 | else | ||
| 2340 | android_draw_glyph_string_background (s, false); | ||
| 2341 | android_draw_glyph_string_foreground (s); | ||
| 2342 | break; | ||
| 2343 | |||
| 2344 | case COMPOSITE_GLYPH: | ||
| 2345 | if (s->for_overlaps || (s->cmp_from > 0 | ||
| 2346 | && ! s->first_glyph->u.cmp.automatic)) | ||
| 2347 | s->background_filled_p = true; | ||
| 2348 | else | ||
| 2349 | android_draw_glyph_string_background (s, true); | ||
| 2350 | android_draw_composite_glyph_string_foreground (s); | ||
| 2351 | break; | ||
| 2352 | |||
| 2353 | case GLYPHLESS_GLYPH: | ||
| 2354 | if (s->for_overlaps) | ||
| 2355 | s->background_filled_p = true; | ||
| 2356 | else | ||
| 2357 | android_draw_glyph_string_background (s, true); | ||
| 2358 | android_draw_glyphless_glyph_string_foreground (s); | ||
| 2359 | break; | ||
| 2360 | |||
| 2361 | default: | ||
| 2362 | emacs_abort (); | ||
| 2363 | } | ||
| 2364 | |||
| 2365 | if (!s->for_overlaps) | ||
| 2366 | { | ||
| 2367 | int area_x, area_y, area_width, area_height; | ||
| 2368 | int area_max_x, decoration_width; | ||
| 2369 | |||
| 2370 | /* Prevent the underline from overwriting surrounding areas | ||
| 2371 | and the fringe. */ | ||
| 2372 | window_box (s->w, s->area, &area_x, &area_y, | ||
| 2373 | &area_width, &area_height); | ||
| 2374 | area_max_x = area_x + area_width - 1; | ||
| 2375 | |||
| 2376 | decoration_width = s->width; | ||
| 2377 | if (!s->row->mode_line_p | ||
| 2378 | && !s->row->tab_line_p | ||
| 2379 | && area_max_x < (s->x + decoration_width - 1)) | ||
| 2380 | decoration_width -= (s->x + decoration_width - 1) - area_max_x; | ||
| 2381 | |||
| 2382 | /* Draw relief if not yet drawn. */ | ||
| 2383 | if (!relief_drawn_p && s->face->box != FACE_NO_BOX) | ||
| 2384 | android_draw_glyph_string_box (s); | ||
| 2385 | |||
| 2386 | /* Draw underline. */ | ||
| 2387 | if (s->face->underline) | ||
| 2388 | { | ||
| 2389 | if (s->face->underline == FACE_UNDER_WAVE) | ||
| 2390 | { | ||
| 2391 | if (s->face->underline_defaulted_p) | ||
| 2392 | android_draw_underwave (s, decoration_width); | ||
| 2393 | else | ||
| 2394 | { | ||
| 2395 | struct android_gc_values xgcv; | ||
| 2396 | android_get_gc_values (s->gc, ANDROID_GC_FOREGROUND, &xgcv); | ||
| 2397 | android_set_foreground (s->gc, s->face->underline_color); | ||
| 2398 | android_draw_underwave (s, decoration_width); | ||
| 2399 | android_set_foreground (s->gc, xgcv.foreground); | ||
| 2400 | } | ||
| 2401 | } | ||
| 2402 | else if (s->face->underline == FACE_UNDER_LINE) | ||
| 2403 | { | ||
| 2404 | unsigned long thickness, position; | ||
| 2405 | int y; | ||
| 2406 | |||
| 2407 | if (s->prev | ||
| 2408 | && s->prev->face->underline == FACE_UNDER_LINE | ||
| 2409 | && (s->prev->face->underline_at_descent_line_p | ||
| 2410 | == s->face->underline_at_descent_line_p) | ||
| 2411 | && (s->prev->face->underline_pixels_above_descent_line | ||
| 2412 | == s->face->underline_pixels_above_descent_line)) | ||
| 2413 | { | ||
| 2414 | /* We use the same underline style as the previous one. */ | ||
| 2415 | thickness = s->prev->underline_thickness; | ||
| 2416 | position = s->prev->underline_position; | ||
| 2417 | } | ||
| 2418 | else | ||
| 2419 | { | ||
| 2420 | struct font *font = font_for_underline_metrics (s); | ||
| 2421 | unsigned long minimum_offset; | ||
| 2422 | bool underline_at_descent_line; | ||
| 2423 | bool use_underline_position_properties; | ||
| 2424 | Lisp_Object val = (WINDOW_BUFFER_LOCAL_VALUE | ||
| 2425 | (Qunderline_minimum_offset, s->w)); | ||
| 2426 | |||
| 2427 | if (FIXNUMP (val)) | ||
| 2428 | minimum_offset = max (0, XFIXNUM (val)); | ||
| 2429 | else | ||
| 2430 | minimum_offset = 1; | ||
| 2431 | |||
| 2432 | val = (WINDOW_BUFFER_LOCAL_VALUE | ||
| 2433 | (Qx_underline_at_descent_line, s->w)); | ||
| 2434 | underline_at_descent_line | ||
| 2435 | = (!(NILP (val) || BASE_EQ (val, Qunbound)) | ||
| 2436 | || s->face->underline_at_descent_line_p); | ||
| 2437 | |||
| 2438 | val = (WINDOW_BUFFER_LOCAL_VALUE | ||
| 2439 | (Qx_use_underline_position_properties, s->w)); | ||
| 2440 | use_underline_position_properties | ||
| 2441 | = !(NILP (val) || BASE_EQ (val, Qunbound)); | ||
| 2442 | |||
| 2443 | /* Get the underline thickness. Default is 1 pixel. */ | ||
| 2444 | if (font && font->underline_thickness > 0) | ||
| 2445 | thickness = font->underline_thickness; | ||
| 2446 | else | ||
| 2447 | thickness = 1; | ||
| 2448 | if (underline_at_descent_line) | ||
| 2449 | position = ((s->height - thickness) | ||
| 2450 | - (s->ybase - s->y) | ||
| 2451 | - s->face->underline_pixels_above_descent_line); | ||
| 2452 | else | ||
| 2453 | { | ||
| 2454 | /* Get the underline position. This is the | ||
| 2455 | recommended vertical offset in pixels from | ||
| 2456 | the baseline to the top of the underline. | ||
| 2457 | This is a signed value according to the | ||
| 2458 | specs, and its default is | ||
| 2459 | |||
| 2460 | ROUND ((maximum descent) / 2), with | ||
| 2461 | ROUND(x) = floor (x + 0.5) */ | ||
| 2462 | |||
| 2463 | if (use_underline_position_properties | ||
| 2464 | && font && font->underline_position >= 0) | ||
| 2465 | position = font->underline_position; | ||
| 2466 | else if (font) | ||
| 2467 | position = (font->descent + 1) / 2; | ||
| 2468 | else | ||
| 2469 | position = minimum_offset; | ||
| 2470 | } | ||
| 2471 | |||
| 2472 | /* Ignore minimum_offset if the amount of pixels was | ||
| 2473 | explicitly specified. */ | ||
| 2474 | if (!s->face->underline_pixels_above_descent_line) | ||
| 2475 | position = max (position, minimum_offset); | ||
| 2476 | } | ||
| 2477 | /* Check the sanity of thickness and position. We should | ||
| 2478 | avoid drawing underline out of the current line area. */ | ||
| 2479 | if (s->y + s->height <= s->ybase + position) | ||
| 2480 | position = (s->height - 1) - (s->ybase - s->y); | ||
| 2481 | if (s->y + s->height < s->ybase + position + thickness) | ||
| 2482 | thickness = (s->y + s->height) - (s->ybase + position); | ||
| 2483 | s->underline_thickness = thickness; | ||
| 2484 | s->underline_position = position; | ||
| 2485 | y = s->ybase + position; | ||
| 2486 | if (s->face->underline_defaulted_p) | ||
| 2487 | android_fill_rectangle (FRAME_ANDROID_WINDOW (s->f), s->gc, | ||
| 2488 | s->x, y, decoration_width, thickness); | ||
| 2489 | else | ||
| 2490 | { | ||
| 2491 | struct android_gc_values xgcv; | ||
| 2492 | android_get_gc_values (s->gc, ANDROID_GC_FOREGROUND, &xgcv); | ||
| 2493 | android_set_foreground (s->gc, s->face->underline_color); | ||
| 2494 | android_fill_rectangle (FRAME_ANDROID_WINDOW (s->f), s->gc, | ||
| 2495 | s->x, y, decoration_width, thickness); | ||
| 2496 | android_set_foreground (s->gc, xgcv.foreground); | ||
| 2497 | } | ||
| 2498 | } | ||
| 2499 | } | ||
| 2500 | /* Draw overline. */ | ||
| 2501 | if (s->face->overline_p) | ||
| 2502 | { | ||
| 2503 | unsigned long dy = 0, h = 1; | ||
| 2504 | |||
| 2505 | if (s->face->overline_color_defaulted_p) | ||
| 2506 | android_fill_rectangle (FRAME_ANDROID_WINDOW (s->f), | ||
| 2507 | s->gc, s->x, s->y + dy, | ||
| 2508 | decoration_width, h); | ||
| 2509 | else | ||
| 2510 | { | ||
| 2511 | struct android_gc_values xgcv; | ||
| 2512 | android_get_gc_values (s->gc, ANDROID_GC_FOREGROUND, &xgcv); | ||
| 2513 | android_set_foreground (s->gc, s->face->overline_color); | ||
| 2514 | android_fill_rectangle (FRAME_ANDROID_WINDOW (s->f), s->gc, s->x, | ||
| 2515 | s->y + dy, decoration_width, h); | ||
| 2516 | android_set_foreground (s->gc, xgcv.foreground); | ||
| 2517 | } | ||
| 2518 | } | ||
| 2519 | |||
| 2520 | /* Draw strike-through. */ | ||
| 2521 | if (s->face->strike_through_p) | ||
| 2522 | { | ||
| 2523 | /* Y-coordinate and height of the glyph string's first | ||
| 2524 | glyph. We cannot use s->y and s->height because those | ||
| 2525 | could be larger if there are taller display elements | ||
| 2526 | (e.g., characters displayed with a larger font) in the | ||
| 2527 | same glyph row. */ | ||
| 2528 | int glyph_y = s->ybase - s->first_glyph->ascent; | ||
| 2529 | int glyph_height = s->first_glyph->ascent + s->first_glyph->descent; | ||
| 2530 | /* Strike-through width and offset from the glyph string's | ||
| 2531 | top edge. */ | ||
| 2532 | unsigned long h = 1; | ||
| 2533 | unsigned long dy = (glyph_height - h) / 2; | ||
| 2534 | |||
| 2535 | if (s->face->strike_through_color_defaulted_p) | ||
| 2536 | android_fill_rectangle (FRAME_ANDROID_WINDOW (s->f), | ||
| 2537 | s->gc, s->x, glyph_y + dy, | ||
| 2538 | s->width, h); | ||
| 2539 | else | ||
| 2540 | { | ||
| 2541 | struct android_gc_values xgcv; | ||
| 2542 | android_get_gc_values (s->gc, ANDROID_GC_FOREGROUND, &xgcv); | ||
| 2543 | android_set_foreground (s->gc, s->face->strike_through_color); | ||
| 2544 | android_fill_rectangle (FRAME_ANDROID_WINDOW (s->f), s->gc, s->x, | ||
| 2545 | glyph_y + dy, decoration_width, h); | ||
| 2546 | android_set_foreground (s->gc, xgcv.foreground); | ||
| 2547 | } | ||
| 2548 | } | ||
| 2549 | |||
| 2550 | if (s->prev) | ||
| 2551 | { | ||
| 2552 | struct glyph_string *prev; | ||
| 2553 | |||
| 2554 | for (prev = s->prev; prev; prev = prev->prev) | ||
| 2555 | if (prev->hl != s->hl | ||
| 2556 | && prev->x + prev->width + prev->right_overhang > s->x) | ||
| 2557 | { | ||
| 2558 | /* As prev was drawn while clipped to its own area, we | ||
| 2559 | must draw the right_overhang part using s->hl now. */ | ||
| 2560 | enum draw_glyphs_face save = prev->hl; | ||
| 2561 | |||
| 2562 | prev->hl = s->hl; | ||
| 2563 | android_set_glyph_string_gc (prev); | ||
| 2564 | android_set_glyph_string_clipping_exactly (s, prev); | ||
| 2565 | if (prev->first_glyph->type == CHAR_GLYPH) | ||
| 2566 | android_draw_glyph_string_foreground (prev); | ||
| 2567 | else | ||
| 2568 | android_draw_composite_glyph_string_foreground (prev); | ||
| 2569 | android_reset_clip_rectangles (prev->f, prev->gc); | ||
| 2570 | prev->hl = save; | ||
| 2571 | prev->num_clips = 0; | ||
| 2572 | } | ||
| 2573 | } | ||
| 2574 | |||
| 2575 | if (s->next) | ||
| 2576 | { | ||
| 2577 | struct glyph_string *next; | ||
| 2578 | |||
| 2579 | for (next = s->next; next; next = next->next) | ||
| 2580 | if (next->hl != s->hl | ||
| 2581 | && next->x - next->left_overhang < s->x + s->width) | ||
| 2582 | { | ||
| 2583 | /* As next will be drawn while clipped to its own area, | ||
| 2584 | we must draw the left_overhang part using s->hl now. */ | ||
| 2585 | enum draw_glyphs_face save = next->hl; | ||
| 2586 | |||
| 2587 | next->hl = s->hl; | ||
| 2588 | android_set_glyph_string_gc (next); | ||
| 2589 | android_set_glyph_string_clipping_exactly (s, next); | ||
| 2590 | if (next->first_glyph->type == CHAR_GLYPH) | ||
| 2591 | android_draw_glyph_string_foreground (next); | ||
| 2592 | else | ||
| 2593 | android_draw_composite_glyph_string_foreground (next); | ||
| 2594 | android_reset_clip_rectangles (next->f, next->gc); | ||
| 2595 | next->hl = save; | ||
| 2596 | next->num_clips = 0; | ||
| 2597 | next->clip_head = s->next; | ||
| 2598 | } | ||
| 2599 | } | ||
| 2600 | } | ||
| 2601 | |||
| 2602 | /* Reset clipping. */ | ||
| 2603 | android_reset_clip_rectangles (s->f, s->gc); | ||
| 2604 | s->num_clips = 0; | ||
| 2605 | |||
| 2606 | /* Set the stippled flag that tells redisplay whether or not a | ||
| 2607 | stipple was actually draw. */ | ||
| 2608 | |||
| 2609 | if (s->first_glyph->type != STRETCH_GLYPH | ||
| 2610 | && s->first_glyph->type != IMAGE_GLYPH | ||
| 2611 | && !s->row->stipple_p) | ||
| 2612 | s->row->stipple_p = s->stippled_p; | ||
| 2613 | } | ||
| 2614 | |||
| 2615 | static void | ||
| 2616 | android_define_frame_cursor (struct frame *f, Emacs_Cursor cursor) | ||
| 2617 | { | ||
| 2618 | /* Not supported, because cursors are not supported on Android. */ | ||
| 2619 | } | ||
| 2620 | |||
| 2621 | static void | ||
| 2622 | android_clear_frame_area (struct frame *f, int x, int y, | ||
| 2623 | int width, int height) | ||
| 2624 | { | ||
| 2625 | android_clear_area (FRAME_ANDROID_WINDOW (f), | ||
| 2626 | x, y, width, height); | ||
| 2627 | } | ||
| 2628 | |||
| 2629 | void | ||
| 2630 | android_clear_under_internal_border (struct frame *f) | ||
| 2631 | { | ||
| 2632 | if (FRAME_INTERNAL_BORDER_WIDTH (f) > 0) | ||
| 2633 | { | ||
| 2634 | int border = FRAME_INTERNAL_BORDER_WIDTH (f); | ||
| 2635 | int width = FRAME_PIXEL_WIDTH (f); | ||
| 2636 | int height = FRAME_PIXEL_HEIGHT (f); | ||
| 2637 | int margin = FRAME_TOP_MARGIN_HEIGHT (f); | ||
| 2638 | int face_id = | ||
| 2639 | (FRAME_PARENT_FRAME (f) | ||
| 2640 | ? (!NILP (Vface_remapping_alist) | ||
| 2641 | ? lookup_basic_face (NULL, f, CHILD_FRAME_BORDER_FACE_ID) | ||
| 2642 | : CHILD_FRAME_BORDER_FACE_ID) | ||
| 2643 | : (!NILP (Vface_remapping_alist) | ||
| 2644 | ? lookup_basic_face (NULL, f, INTERNAL_BORDER_FACE_ID) | ||
| 2645 | : INTERNAL_BORDER_FACE_ID)); | ||
| 2646 | struct face *face = FACE_FROM_ID_OR_NULL (f, face_id); | ||
| 2647 | |||
| 2648 | if (face) | ||
| 2649 | { | ||
| 2650 | unsigned long color = face->background; | ||
| 2651 | struct android_gc *gc = f->output_data.android->normal_gc; | ||
| 2652 | |||
| 2653 | android_set_foreground (gc, color); | ||
| 2654 | android_fill_rectangle (FRAME_ANDROID_WINDOW (f), gc, 0, margin, | ||
| 2655 | width, border); | ||
| 2656 | android_fill_rectangle (FRAME_ANDROID_WINDOW (f), gc, 0, 0, | ||
| 2657 | border, height); | ||
| 2658 | android_fill_rectangle (FRAME_ANDROID_WINDOW (f), gc, width - border, | ||
| 2659 | 0, border, height); | ||
| 2660 | android_fill_rectangle (FRAME_ANDROID_WINDOW (f), gc, 0, | ||
| 2661 | height - border, width, border); | ||
| 2662 | android_set_foreground (gc, FRAME_FOREGROUND_PIXEL (f)); | ||
| 2663 | } | ||
| 2664 | else | ||
| 2665 | { | ||
| 2666 | android_clear_area (FRAME_ANDROID_WINDOW (f), 0, 0, | ||
| 2667 | border, height); | ||
| 2668 | android_clear_area (FRAME_ANDROID_WINDOW (f), 0, | ||
| 2669 | margin, width, border); | ||
| 2670 | android_clear_area (FRAME_ANDROID_WINDOW (f), width - border, | ||
| 2671 | 0, border, height); | ||
| 2672 | android_clear_area (FRAME_ANDROID_WINDOW (f), 0, | ||
| 2673 | height - border, width, border); | ||
| 2674 | } | ||
| 2675 | } | ||
| 2676 | } | ||
| 2677 | |||
| 2678 | static void | ||
| 2679 | android_draw_hollow_cursor (struct window *w, struct glyph_row *row) | ||
| 2680 | { | ||
| 2681 | struct frame *f = XFRAME (WINDOW_FRAME (w)); | ||
| 2682 | struct android_display_info *dpyinfo = FRAME_DISPLAY_INFO (f); | ||
| 2683 | int x, y, wd, h; | ||
| 2684 | struct android_gc_values xgcv; | ||
| 2685 | struct glyph *cursor_glyph; | ||
| 2686 | struct android_gc *gc; | ||
| 2687 | |||
| 2688 | /* Get the glyph the cursor is on. If we can't tell because | ||
| 2689 | the current matrix is invalid or such, give up. */ | ||
| 2690 | cursor_glyph = get_phys_cursor_glyph (w); | ||
| 2691 | if (cursor_glyph == NULL) | ||
| 2692 | return; | ||
| 2693 | |||
| 2694 | /* Compute frame-relative coordinates for phys cursor. */ | ||
| 2695 | get_phys_cursor_geometry (w, row, cursor_glyph, &x, &y, &h); | ||
| 2696 | wd = w->phys_cursor_width - 1; | ||
| 2697 | |||
| 2698 | /* The foreground of cursor_gc is typically the same as the normal | ||
| 2699 | background color, which can cause the cursor box to be invisible. */ | ||
| 2700 | xgcv.foreground = f->output_data.android->cursor_pixel; | ||
| 2701 | if (dpyinfo->scratch_cursor_gc) | ||
| 2702 | android_change_gc (dpyinfo->scratch_cursor_gc, | ||
| 2703 | ANDROID_GC_FOREGROUND, &xgcv); | ||
| 2704 | else | ||
| 2705 | dpyinfo->scratch_cursor_gc | ||
| 2706 | = android_create_gc (ANDROID_GC_FOREGROUND, &xgcv); | ||
| 2707 | gc = dpyinfo->scratch_cursor_gc; | ||
| 2708 | |||
| 2709 | /* When on R2L character, show cursor at the right edge of the | ||
| 2710 | glyph, unless the cursor box is as wide as the glyph or wider | ||
| 2711 | (the latter happens when x-stretch-cursor is non-nil). */ | ||
| 2712 | if ((cursor_glyph->resolved_level & 1) != 0 | ||
| 2713 | && cursor_glyph->pixel_width > wd) | ||
| 2714 | { | ||
| 2715 | x += cursor_glyph->pixel_width - wd; | ||
| 2716 | if (wd > 0) | ||
| 2717 | wd -= 1; | ||
| 2718 | } | ||
| 2719 | /* Set clipping, draw the rectangle, and reset clipping again. */ | ||
| 2720 | android_clip_to_row (w, row, TEXT_AREA, gc); | ||
| 2721 | android_draw_rectangle (FRAME_ANDROID_WINDOW (f), gc, x, y, wd, h - 1); | ||
| 2722 | android_reset_clip_rectangles (f, gc); | ||
| 2723 | } | ||
| 2724 | |||
| 2725 | static void | ||
| 2726 | android_draw_bar_cursor (struct window *w, struct glyph_row *row, int width, | ||
| 2727 | enum text_cursor_kinds kind) | ||
| 2728 | { | ||
| 2729 | struct frame *f = XFRAME (w->frame); | ||
| 2730 | struct glyph *cursor_glyph; | ||
| 2731 | int cursor_start_y; | ||
| 2732 | |||
| 2733 | /* If cursor is out of bounds, don't draw garbage. This can happen | ||
| 2734 | in mini-buffer windows when switching between echo area glyphs | ||
| 2735 | and mini-buffer. */ | ||
| 2736 | cursor_glyph = get_phys_cursor_glyph (w); | ||
| 2737 | if (cursor_glyph == NULL) | ||
| 2738 | return; | ||
| 2739 | |||
| 2740 | /* Experimental avoidance of cursor on xwidget. */ | ||
| 2741 | if (cursor_glyph->type == XWIDGET_GLYPH) | ||
| 2742 | return; | ||
| 2743 | |||
| 2744 | /* If on an image, draw like a normal cursor. That's usually better | ||
| 2745 | visible than drawing a bar, esp. if the image is large so that | ||
| 2746 | the bar might not be in the window. */ | ||
| 2747 | if (cursor_glyph->type == IMAGE_GLYPH) | ||
| 2748 | { | ||
| 2749 | struct glyph_row *r; | ||
| 2750 | r = MATRIX_ROW (w->current_matrix, w->phys_cursor.vpos); | ||
| 2751 | draw_phys_cursor_glyph (w, r, DRAW_CURSOR); | ||
| 2752 | } | ||
| 2753 | else | ||
| 2754 | { | ||
| 2755 | struct android_gc *gc = FRAME_DISPLAY_INFO (f)->scratch_cursor_gc; | ||
| 2756 | unsigned long mask = ANDROID_GC_FOREGROUND | ANDROID_GC_BACKGROUND; | ||
| 2757 | struct face *face = FACE_FROM_ID (f, cursor_glyph->face_id); | ||
| 2758 | struct android_gc_values xgcv; | ||
| 2759 | |||
| 2760 | /* If the glyph's background equals the color we normally draw | ||
| 2761 | the bars cursor in, the bar cursor in its normal color is | ||
| 2762 | invisible. Use the glyph's foreground color instead in this | ||
| 2763 | case, on the assumption that the glyph's colors are chosen so | ||
| 2764 | that the glyph is legible. */ | ||
| 2765 | if (face->background == f->output_data.android->cursor_pixel) | ||
| 2766 | xgcv.background = xgcv.foreground = face->foreground; | ||
| 2767 | else | ||
| 2768 | xgcv.background = xgcv.foreground = f->output_data.android->cursor_pixel; | ||
| 2769 | |||
| 2770 | if (gc) | ||
| 2771 | android_change_gc (gc, mask, &xgcv); | ||
| 2772 | else | ||
| 2773 | { | ||
| 2774 | gc = android_create_gc (mask, &xgcv); | ||
| 2775 | FRAME_DISPLAY_INFO (f)->scratch_cursor_gc = gc; | ||
| 2776 | } | ||
| 2777 | |||
| 2778 | android_clip_to_row (w, row, TEXT_AREA, gc); | ||
| 2779 | |||
| 2780 | if (kind == BAR_CURSOR) | ||
| 2781 | { | ||
| 2782 | int x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x); | ||
| 2783 | |||
| 2784 | if (width < 0) | ||
| 2785 | width = FRAME_CURSOR_WIDTH (f); | ||
| 2786 | width = min (cursor_glyph->pixel_width, width); | ||
| 2787 | |||
| 2788 | w->phys_cursor_width = width; | ||
| 2789 | |||
| 2790 | /* If the character under cursor is R2L, draw the bar cursor | ||
| 2791 | on the right of its glyph, rather than on the left. */ | ||
| 2792 | if ((cursor_glyph->resolved_level & 1) != 0) | ||
| 2793 | x += cursor_glyph->pixel_width - width; | ||
| 2794 | |||
| 2795 | android_fill_rectangle (FRAME_ANDROID_WINDOW (f), gc, x, | ||
| 2796 | WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y), | ||
| 2797 | width, row->height); | ||
| 2798 | } | ||
| 2799 | else /* HBAR_CURSOR */ | ||
| 2800 | { | ||
| 2801 | int dummy_x, dummy_y, dummy_h; | ||
| 2802 | int x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x); | ||
| 2803 | |||
| 2804 | if (width < 0) | ||
| 2805 | width = row->height; | ||
| 2806 | |||
| 2807 | width = min (row->height, width); | ||
| 2808 | |||
| 2809 | get_phys_cursor_geometry (w, row, cursor_glyph, &dummy_x, | ||
| 2810 | &dummy_y, &dummy_h); | ||
| 2811 | |||
| 2812 | cursor_start_y = WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y | ||
| 2813 | + row->height - width); | ||
| 2814 | |||
| 2815 | if ((cursor_glyph->resolved_level & 1) != 0 | ||
| 2816 | && cursor_glyph->pixel_width > w->phys_cursor_width - 1) | ||
| 2817 | x += cursor_glyph->pixel_width - w->phys_cursor_width + 1; | ||
| 2818 | android_fill_rectangle (FRAME_ANDROID_WINDOW (f), gc, x, | ||
| 2819 | cursor_start_y, | ||
| 2820 | w->phys_cursor_width - 1, width); | ||
| 2821 | } | ||
| 2822 | |||
| 2823 | android_reset_clip_rectangles (f, gc); | ||
| 2824 | } | ||
| 2825 | } | ||
| 2826 | |||
| 2827 | static void | ||
| 2828 | android_draw_window_cursor (struct window *w, struct glyph_row *glyph_row, | ||
| 2829 | int x, int y, enum text_cursor_kinds cursor_type, | ||
| 2830 | int cursor_width, bool on_p, bool active_p) | ||
| 2831 | { | ||
| 2832 | if (on_p) | ||
| 2833 | { | ||
| 2834 | w->phys_cursor_type = cursor_type; | ||
| 2835 | w->phys_cursor_on_p = true; | ||
| 2836 | |||
| 2837 | if (glyph_row->exact_window_width_line_p | ||
| 2838 | && (glyph_row->reversed_p | ||
| 2839 | ? (w->phys_cursor.hpos < 0) | ||
| 2840 | : (w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA]))) | ||
| 2841 | { | ||
| 2842 | glyph_row->cursor_in_fringe_p = true; | ||
| 2843 | draw_fringe_bitmap (w, glyph_row, glyph_row->reversed_p); | ||
| 2844 | } | ||
| 2845 | else | ||
| 2846 | { | ||
| 2847 | switch (cursor_type) | ||
| 2848 | { | ||
| 2849 | case HOLLOW_BOX_CURSOR: | ||
| 2850 | android_draw_hollow_cursor (w, glyph_row); | ||
| 2851 | break; | ||
| 2852 | |||
| 2853 | case FILLED_BOX_CURSOR: | ||
| 2854 | draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR); | ||
| 2855 | break; | ||
| 2856 | |||
| 2857 | case BAR_CURSOR: | ||
| 2858 | android_draw_bar_cursor (w, glyph_row, cursor_width, BAR_CURSOR); | ||
| 2859 | break; | ||
| 2860 | |||
| 2861 | case HBAR_CURSOR: | ||
| 2862 | android_draw_bar_cursor (w, glyph_row, cursor_width, HBAR_CURSOR); | ||
| 2863 | break; | ||
| 2864 | |||
| 2865 | case NO_CURSOR: | ||
| 2866 | w->phys_cursor_width = 0; | ||
| 2867 | break; | ||
| 2868 | |||
| 2869 | default: | ||
| 2870 | emacs_abort (); | ||
| 2871 | } | ||
| 2872 | } | ||
| 2873 | } | ||
| 2874 | } | ||
| 2875 | |||
| 2876 | static void | ||
| 2877 | android_draw_vertical_window_border (struct window *w, int x, int y0, int y1) | ||
| 2878 | { | ||
| 2879 | struct frame *f = XFRAME (WINDOW_FRAME (w)); | ||
| 2880 | struct face *face; | ||
| 2881 | |||
| 2882 | face = FACE_FROM_ID_OR_NULL (f, VERTICAL_BORDER_FACE_ID); | ||
| 2883 | if (face) | ||
| 2884 | android_set_foreground (f->output_data.android->normal_gc, | ||
| 2885 | face->foreground); | ||
| 2886 | |||
| 2887 | android_draw_line (FRAME_ANDROID_WINDOW (f), | ||
| 2888 | f->output_data.android->normal_gc, | ||
| 2889 | x, y0, x, y1); | ||
| 2890 | } | ||
| 2891 | |||
| 2892 | static void | ||
| 2893 | android_draw_window_divider (struct window *w, int x0, int x1, int y0, int y1) | ||
| 2894 | { | ||
| 2895 | struct frame *f = XFRAME (WINDOW_FRAME (w)); | ||
| 2896 | struct face *face = FACE_FROM_ID_OR_NULL (f, WINDOW_DIVIDER_FACE_ID); | ||
| 2897 | struct face *face_first | ||
| 2898 | = FACE_FROM_ID_OR_NULL (f, WINDOW_DIVIDER_FIRST_PIXEL_FACE_ID); | ||
| 2899 | struct face *face_last | ||
| 2900 | = FACE_FROM_ID_OR_NULL (f, WINDOW_DIVIDER_LAST_PIXEL_FACE_ID); | ||
| 2901 | unsigned long color = face ? face->foreground : FRAME_FOREGROUND_PIXEL (f); | ||
| 2902 | unsigned long color_first = (face_first | ||
| 2903 | ? face_first->foreground | ||
| 2904 | : FRAME_FOREGROUND_PIXEL (f)); | ||
| 2905 | unsigned long color_last = (face_last | ||
| 2906 | ? face_last->foreground | ||
| 2907 | : FRAME_FOREGROUND_PIXEL (f)); | ||
| 2908 | |||
| 2909 | if ((y1 - y0 > x1 - x0) && (x1 - x0 >= 3)) | ||
| 2910 | /* A vertical divider, at least three pixels wide: Draw first and | ||
| 2911 | last pixels differently. */ | ||
| 2912 | { | ||
| 2913 | android_set_foreground (f->output_data.android->normal_gc, | ||
| 2914 | color_first); | ||
| 2915 | android_fill_rectangle (FRAME_ANDROID_WINDOW (f), | ||
| 2916 | f->output_data.android->normal_gc, | ||
| 2917 | x0, y0, 1, y1 - y0); | ||
| 2918 | android_set_foreground (f->output_data.android->normal_gc, | ||
| 2919 | color); | ||
| 2920 | android_fill_rectangle (FRAME_ANDROID_WINDOW (f), | ||
| 2921 | f->output_data.android->normal_gc, | ||
| 2922 | x0 + 1, y0, x1 - x0 - 2, y1 - y0); | ||
| 2923 | android_set_foreground (f->output_data.android->normal_gc, | ||
| 2924 | color_last); | ||
| 2925 | android_fill_rectangle (FRAME_ANDROID_WINDOW (f), | ||
| 2926 | f->output_data.android->normal_gc, | ||
| 2927 | x1 - 1, y0, 1, y1 - y0); | ||
| 2928 | } | ||
| 2929 | else if ((x1 - x0 > y1 - y0) && (y1 - y0 >= 3)) | ||
| 2930 | /* A horizontal divider, at least three pixels high: Draw first | ||
| 2931 | and last pixels differently. */ | ||
| 2932 | { | ||
| 2933 | android_set_foreground (f->output_data.android->normal_gc, | ||
| 2934 | color_first); | ||
| 2935 | android_fill_rectangle (FRAME_ANDROID_WINDOW (f), | ||
| 2936 | f->output_data.android->normal_gc, | ||
| 2937 | x0, y0, x1 - x0, 1); | ||
| 2938 | android_set_foreground (f->output_data.android->normal_gc, color); | ||
| 2939 | android_fill_rectangle (FRAME_ANDROID_WINDOW (f), | ||
| 2940 | f->output_data.android->normal_gc, | ||
| 2941 | x0, y0 + 1, x1 - x0, y1 - y0 - 2); | ||
| 2942 | android_set_foreground (f->output_data.android->normal_gc, | ||
| 2943 | color_last); | ||
| 2944 | android_fill_rectangle (FRAME_ANDROID_WINDOW (f), | ||
| 2945 | f->output_data.android->normal_gc, | ||
| 2946 | x0, y1 - 1, x1 - x0, 1); | ||
| 2947 | } | ||
| 2948 | else | ||
| 2949 | { | ||
| 2950 | /* In any other case do not draw the first and last pixels | ||
| 2951 | differently. */ | ||
| 2952 | android_set_foreground (f->output_data.android->normal_gc, color); | ||
| 2953 | android_fill_rectangle (FRAME_ANDROID_WINDOW (f), | ||
| 2954 | f->output_data.android->normal_gc, | ||
| 2955 | x0, y0, x1 - x0, y1 - y0); | ||
| 2956 | } | ||
| 2957 | } | ||
| 2958 | |||
| 2959 | |||
| 2960 | |||
| 2961 | extern frame_parm_handler android_frame_parm_handlers[]; | ||
| 2962 | |||
| 2963 | #endif /* !ANDROID_STUBIFY */ | ||
| 2964 | |||
| 2965 | static struct redisplay_interface android_redisplay_interface = | ||
| 2966 | { | ||
| 2967 | #ifndef ANDROID_STUBIFY | ||
| 2968 | android_frame_parm_handlers, | ||
| 2969 | gui_produce_glyphs, | ||
| 2970 | gui_write_glyphs, | ||
| 2971 | gui_insert_glyphs, | ||
| 2972 | gui_clear_end_of_line, | ||
| 2973 | android_scroll_run, | ||
| 2974 | android_after_update_window_line, | ||
| 2975 | NULL, /* update_window_begin */ | ||
| 2976 | NULL, /* update_window_end */ | ||
| 2977 | android_flip_and_flush, | ||
| 2978 | gui_clear_window_mouse_face, | ||
| 2979 | gui_get_glyph_overhangs, | ||
| 2980 | gui_fix_overlapping_area, | ||
| 2981 | android_draw_fringe_bitmap, | ||
| 2982 | NULL, /* define_fringe_bitmap */ | ||
| 2983 | NULL, /* destroy_fringe_bitmap */ | ||
| 2984 | android_compute_glyph_string_overhangs, | ||
| 2985 | android_draw_glyph_string, | ||
| 2986 | android_define_frame_cursor, | ||
| 2987 | android_clear_frame_area, | ||
| 2988 | android_clear_under_internal_border, | ||
| 2989 | android_draw_window_cursor, | ||
| 2990 | android_draw_vertical_window_border, | ||
| 2991 | android_draw_window_divider, | ||
| 2992 | NULL, | ||
| 2993 | NULL, | ||
| 2994 | NULL, | ||
| 2995 | android_default_font_parameter, | ||
| 2996 | #endif | ||
| 2997 | }; | ||
| 2998 | |||
| 2999 | |||
| 3000 | |||
| 3001 | void | ||
| 3002 | frame_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y) | ||
| 3003 | { | ||
| 3004 | /* This cannot be implemented on Android, and as such is left | ||
| 3005 | blank. */ | ||
| 3006 | } | ||
| 3007 | |||
| 3008 | char * | ||
| 3009 | get_keysym_name (int keysym) | ||
| 3010 | { | ||
| 3011 | return (char *) "UNKNOWN KEYSYM"; | ||
| 3012 | } | ||
| 3013 | |||
| 3014 | |||
| 3015 | |||
| 3016 | /* Create a struct terminal, initialize it with the Android specific | ||
| 3017 | functions and make DISPLAY->TERMINAL point to it. */ | ||
| 3018 | |||
| 3019 | static struct terminal * | ||
| 3020 | android_create_terminal (struct android_display_info *dpyinfo) | ||
| 3021 | { | ||
| 3022 | struct terminal *terminal; | ||
| 3023 | |||
| 3024 | terminal = create_terminal (output_android, | ||
| 3025 | &android_redisplay_interface); | ||
| 3026 | terminal->display_info.android = dpyinfo; | ||
| 3027 | dpyinfo->terminal = terminal; | ||
| 3028 | |||
| 3029 | /* kboard is initialized in android_term_init. */ | ||
| 3030 | |||
| 3031 | #ifndef ANDROID_STUBIFY | ||
| 3032 | |||
| 3033 | terminal->clear_frame_hook = android_clear_frame; | ||
| 3034 | terminal->ring_bell_hook = android_ring_bell; | ||
| 3035 | terminal->toggle_invisible_pointer_hook | ||
| 3036 | = android_toggle_invisible_pointer; | ||
| 3037 | terminal->update_begin_hook = android_update_begin; | ||
| 3038 | terminal->update_end_hook = android_update_end; | ||
| 3039 | terminal->read_socket_hook = android_read_socket; | ||
| 3040 | terminal->frame_up_to_date_hook = android_frame_up_to_date; | ||
| 3041 | terminal->buffer_flipping_unblocked_hook | ||
| 3042 | = android_buffer_flipping_unblocked_hook; | ||
| 3043 | terminal->defined_color_hook = android_defined_color; | ||
| 3044 | terminal->query_frame_background_color | ||
| 3045 | = android_query_frame_background_color; | ||
| 3046 | terminal->query_colors = android_query_colors; | ||
| 3047 | terminal->mouse_position_hook = android_mouse_position; | ||
| 3048 | terminal->get_focus_frame = android_get_focus_frame; | ||
| 3049 | terminal->focus_frame_hook = android_focus_frame; | ||
| 3050 | terminal->frame_rehighlight_hook = android_frame_rehighlight; | ||
| 3051 | terminal->frame_raise_lower_hook = android_frame_raise_lower; | ||
| 3052 | terminal->frame_visible_invisible_hook | ||
| 3053 | = android_make_frame_visible_invisible; | ||
| 3054 | terminal->fullscreen_hook = android_fullscreen_hook; | ||
| 3055 | terminal->iconify_frame_hook = android_iconify_frame; | ||
| 3056 | terminal->set_window_size_hook = android_set_window_size; | ||
| 3057 | terminal->set_frame_offset_hook = android_set_offset; | ||
| 3058 | terminal->set_frame_alpha_hook = android_set_alpha; | ||
| 3059 | terminal->set_new_font_hook = android_new_font; | ||
| 3060 | terminal->set_bitmap_icon_hook = android_bitmap_icon; | ||
| 3061 | terminal->implicit_set_name_hook = android_implicitly_set_name; | ||
| 3062 | /* terminal->menu_show_hook = android_menu_show; XXX */ | ||
| 3063 | terminal->change_tab_bar_height_hook = android_change_tab_bar_height; | ||
| 3064 | terminal->change_tool_bar_height_hook = android_change_tool_bar_height; | ||
| 3065 | /* terminal->set_vertical_scroll_bar_hook */ | ||
| 3066 | /* = android_set_vertical_scroll_bar; */ | ||
| 3067 | /* terminal->set_horizontal_scroll_bar_hook */ | ||
| 3068 | /* = android_set_horizontal_scroll_bar; */ | ||
| 3069 | terminal->set_scroll_bar_default_width_hook | ||
| 3070 | = android_set_scroll_bar_default_width; | ||
| 3071 | terminal->set_scroll_bar_default_height_hook | ||
| 3072 | = android_set_scroll_bar_default_height; | ||
| 3073 | /* terminal->condemn_scroll_bars_hook = android_condemn_scroll_bars; */ | ||
| 3074 | /* terminal->redeem_scroll_bars_hook = android_redeem_scroll_bars; */ | ||
| 3075 | /* terminal->judge_scroll_bars_hook = android_judge_scroll_bars; */ | ||
| 3076 | terminal->free_pixmap = android_free_pixmap_hook; | ||
| 3077 | terminal->delete_frame_hook = android_delete_frame; | ||
| 3078 | terminal->delete_terminal_hook = android_delete_terminal; | ||
| 3079 | |||
| 3080 | #else | ||
| 3081 | emacs_abort (); | ||
| 3082 | #endif | ||
| 3083 | |||
| 3084 | return terminal; | ||
| 3085 | } | ||
| 3086 | |||
| 3087 | /* Initialize the Android terminal interface. The display connection | ||
| 3088 | has already been set up by the system at this point. */ | ||
| 3089 | |||
| 3090 | void | ||
| 3091 | android_term_init (void) | ||
| 3092 | { | ||
| 3093 | struct terminal *terminal; | ||
| 3094 | struct android_display_info *dpyinfo; | ||
| 3095 | Lisp_Object color_file, color_map; | ||
| 3096 | |||
| 3097 | dpyinfo = xzalloc (sizeof *dpyinfo); | ||
| 3098 | terminal = android_create_terminal (dpyinfo); | ||
| 3099 | terminal->kboard = allocate_kboard (Qandroid); | ||
| 3100 | terminal->kboard->reference_count++; | ||
| 3101 | |||
| 3102 | dpyinfo->n_planes = 24; | ||
| 3103 | |||
| 3104 | /* This function should only be called once at startup. */ | ||
| 3105 | eassert (!x_display_list); | ||
| 3106 | x_display_list = dpyinfo; | ||
| 3107 | |||
| 3108 | dpyinfo->name_list_element | ||
| 3109 | = Fcons (build_pure_c_string ("android"), Qnil); | ||
| 3110 | |||
| 3111 | color_file = Fexpand_file_name (build_string ("rgb.txt"), | ||
| 3112 | Vdata_directory); | ||
| 3113 | color_map = Fx_load_color_file (color_file); | ||
| 3114 | |||
| 3115 | if (NILP (color_map)) | ||
| 3116 | fatal ("Could not read %s.\n", SDATA (color_file)); | ||
| 3117 | |||
| 3118 | dpyinfo->color_map = color_map; | ||
| 3119 | |||
| 3120 | /* TODO! */ | ||
| 3121 | dpyinfo->resx = 96.0; | ||
| 3122 | dpyinfo->resy = 96.0; | ||
| 3123 | |||
| 3124 | /* https://lists.gnu.org/r/emacs-devel/2015-11/msg00194.html */ | ||
| 3125 | dpyinfo->smallest_font_height = 1; | ||
| 3126 | dpyinfo->smallest_char_width = 1; | ||
| 3127 | |||
| 3128 | terminal->name = xstrdup ("android"); | ||
| 3129 | |||
| 3130 | /* The display "connection" is now set up, and it must never go | ||
| 3131 | away. */ | ||
| 3132 | terminal->reference_count = 30000; | ||
| 3133 | } | ||
| 3134 | |||
| 3135 | |||
| 3136 | |||
| 3137 | void | ||
| 3138 | syms_of_androidterm (void) | ||
| 3139 | { | ||
| 3140 | Fprovide (Qandroid, Qnil); | ||
| 3141 | |||
| 3142 | DEFVAR_BOOL ("x-use-underline-position-properties", | ||
| 3143 | x_use_underline_position_properties, | ||
| 3144 | doc: /* SKIP: real doc in xterm.c. */); | ||
| 3145 | x_use_underline_position_properties = true; | ||
| 3146 | DEFSYM (Qx_use_underline_position_properties, | ||
| 3147 | "x-use-underline-position-properties"); | ||
| 3148 | |||
| 3149 | DEFVAR_BOOL ("x-underline-at-descent-line", | ||
| 3150 | x_underline_at_descent_line, | ||
| 3151 | doc: /* SKIP: real doc in xterm.c. */); | ||
| 3152 | x_underline_at_descent_line = false; | ||
| 3153 | DEFSYM (Qx_underline_at_descent_line, "x-underline-at-descent-line"); | ||
| 3154 | } | ||
| 3155 | |||
| 3156 | void | ||
| 3157 | mark_androidterm (void) | ||
| 3158 | { | ||
| 3159 | if (x_display_list) | ||
| 3160 | mark_object (x_display_list->color_map); | ||
| 3161 | } | ||