diff options
| author | Andrea Corallo | 2020-08-13 12:22:07 +0200 |
|---|---|---|
| committer | Andrea Corallo | 2020-08-13 12:22:07 +0200 |
| commit | 46e7613ad3b88807d25cfab3d78bf46c9e2fe13e (patch) | |
| tree | a7b560c36e097660536697c9d0057c9273d779b2 /src | |
| parent | f6502f959253b8f705e324e137c2933c5a668f62 (diff) | |
| parent | e9eafd22681b8e95d8d642def0512d9290564206 (diff) | |
| download | emacs-46e7613ad3b88807d25cfab3d78bf46c9e2fe13e.tar.gz emacs-46e7613ad3b88807d25cfab3d78bf46c9e2fe13e.zip | |
Merge remote-tracking branch 'savannah/master' into HEAD
Diffstat (limited to 'src')
| -rw-r--r-- | src/Makefile.in | 1 | ||||
| -rw-r--r-- | src/bytecode.c | 1 | ||||
| -rw-r--r-- | src/composite.c | 1 | ||||
| -rw-r--r-- | src/emacs.c | 3 | ||||
| -rw-r--r-- | src/fns.c | 67 | ||||
| -rw-r--r-- | src/json.c | 4 | ||||
| -rw-r--r-- | src/lisp.h | 24 | ||||
| -rw-r--r-- | src/macfont.m | 88 | ||||
| -rw-r--r-- | src/minibuf.c | 3 | ||||
| -rw-r--r-- | src/nsterm.m | 21 | ||||
| -rw-r--r-- | src/nsxwidget.h | 80 | ||||
| -rw-r--r-- | src/nsxwidget.m | 601 | ||||
| -rw-r--r-- | src/pdumper.c | 320 | ||||
| -rw-r--r-- | src/pdumper.h | 1 | ||||
| -rw-r--r-- | src/timefns.c | 2 | ||||
| -rw-r--r-- | src/xfaces.c | 20 | ||||
| -rw-r--r-- | src/xwidget.c | 253 | ||||
| -rw-r--r-- | src/xwidget.h | 48 |
18 files changed, 1242 insertions, 296 deletions
diff --git a/src/Makefile.in b/src/Makefile.in index 3cc9d594144..63a4aa80e93 100644 --- a/src/Makefile.in +++ b/src/Makefile.in | |||
| @@ -438,6 +438,7 @@ SOME_MACHINE_OBJECTS = dosfns.o msdos.o \ | |||
| 438 | xterm.o xfns.o xmenu.o xselect.o xrdb.o xsmfns.o fringe.o image.o \ | 438 | xterm.o xfns.o xmenu.o xselect.o xrdb.o xsmfns.o fringe.o image.o \ |
| 439 | fontset.o dbusbind.o cygw32.o \ | 439 | fontset.o dbusbind.o cygw32.o \ |
| 440 | nsterm.o nsfns.o nsmenu.o nsselect.o nsimage.o nsfont.o macfont.o \ | 440 | nsterm.o nsfns.o nsmenu.o nsselect.o nsimage.o nsfont.o macfont.o \ |
| 441 | nsxwidget.o \ | ||
| 441 | w32.o w32console.o w32cygwinx.o w32fns.o w32heap.o w32inevt.o w32notify.o \ | 442 | w32.o w32console.o w32cygwinx.o w32fns.o w32heap.o w32inevt.o w32notify.o \ |
| 442 | w32menu.o w32proc.o w32reg.o w32select.o w32term.o w32xfns.o \ | 443 | w32menu.o w32proc.o w32reg.o w32select.o w32term.o w32xfns.o \ |
| 443 | w16select.o widget.o xfont.o ftfont.o xftfont.o gtkutil.o \ | 444 | w16select.o widget.o xfont.o ftfont.o xftfont.o gtkutil.o \ |
diff --git a/src/bytecode.c b/src/bytecode.c index 1913a4812a0..1c3b6eac0d1 100644 --- a/src/bytecode.c +++ b/src/bytecode.c | |||
| @@ -1401,7 +1401,6 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth, | |||
| 1401 | Lisp_Object v1 = POP; | 1401 | Lisp_Object v1 = POP; |
| 1402 | ptrdiff_t i; | 1402 | ptrdiff_t i; |
| 1403 | struct Lisp_Hash_Table *h = XHASH_TABLE (jmp_table); | 1403 | struct Lisp_Hash_Table *h = XHASH_TABLE (jmp_table); |
| 1404 | hash_rehash_if_needed (h); | ||
| 1405 | 1404 | ||
| 1406 | /* h->count is a faster approximation for HASH_TABLE_SIZE (h) | 1405 | /* h->count is a faster approximation for HASH_TABLE_SIZE (h) |
| 1407 | here. */ | 1406 | here. */ |
diff --git a/src/composite.c b/src/composite.c index f96f0b77726..ec2b8328f78 100644 --- a/src/composite.c +++ b/src/composite.c | |||
| @@ -652,7 +652,6 @@ Lisp_Object | |||
| 652 | composition_gstring_put_cache (Lisp_Object gstring, ptrdiff_t len) | 652 | composition_gstring_put_cache (Lisp_Object gstring, ptrdiff_t len) |
| 653 | { | 653 | { |
| 654 | struct Lisp_Hash_Table *h = XHASH_TABLE (gstring_hash_table); | 654 | struct Lisp_Hash_Table *h = XHASH_TABLE (gstring_hash_table); |
| 655 | hash_rehash_if_needed (h); | ||
| 656 | Lisp_Object header = LGSTRING_HEADER (gstring); | 655 | Lisp_Object header = LGSTRING_HEADER (gstring); |
| 657 | Lisp_Object hash = h->test.hashfn (header, h); | 656 | Lisp_Object hash = h->test.hashfn (header, h); |
| 658 | if (len < 0) | 657 | if (len < 0) |
diff --git a/src/emacs.c b/src/emacs.c index 8c252276352..288ddb47bd7 100644 --- a/src/emacs.c +++ b/src/emacs.c | |||
| @@ -1551,6 +1551,7 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem | |||
| 1551 | if (!initialized) | 1551 | if (!initialized) |
| 1552 | { | 1552 | { |
| 1553 | init_alloc_once (); | 1553 | init_alloc_once (); |
| 1554 | init_pdumper_once (); | ||
| 1554 | init_obarray_once (); | 1555 | init_obarray_once (); |
| 1555 | init_eval_once (); | 1556 | init_eval_once (); |
| 1556 | init_charset_once (); | 1557 | init_charset_once (); |
| @@ -1877,7 +1878,6 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem | |||
| 1877 | syms_of_xfns (); | 1878 | syms_of_xfns (); |
| 1878 | syms_of_xmenu (); | 1879 | syms_of_xmenu (); |
| 1879 | syms_of_fontset (); | 1880 | syms_of_fontset (); |
| 1880 | syms_of_xwidget (); | ||
| 1881 | syms_of_xsettings (); | 1881 | syms_of_xsettings (); |
| 1882 | #ifdef HAVE_X_SM | 1882 | #ifdef HAVE_X_SM |
| 1883 | syms_of_xsmfns (); | 1883 | syms_of_xsmfns (); |
| @@ -1954,6 +1954,7 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem | |||
| 1954 | #endif /* HAVE_W32NOTIFY */ | 1954 | #endif /* HAVE_W32NOTIFY */ |
| 1955 | #endif /* WINDOWSNT */ | 1955 | #endif /* WINDOWSNT */ |
| 1956 | 1956 | ||
| 1957 | syms_of_xwidget (); | ||
| 1957 | syms_of_threads (); | 1958 | syms_of_threads (); |
| 1958 | syms_of_profiler (); | 1959 | syms_of_profiler (); |
| 1959 | syms_of_pdumper (); | 1960 | syms_of_pdumper (); |
| @@ -4248,50 +4248,31 @@ maybe_resize_hash_table (struct Lisp_Hash_Table *h) | |||
| 4248 | 4248 | ||
| 4249 | /* Recompute the hashes (and hence also the "next" pointers). | 4249 | /* Recompute the hashes (and hence also the "next" pointers). |
| 4250 | Normally there's never a need to recompute hashes. | 4250 | Normally there's never a need to recompute hashes. |
| 4251 | This is done only on first-access to a hash-table loaded from | 4251 | This is done only on first access to a hash-table loaded from |
| 4252 | the "pdump", because the object's addresses may have changed, thus | 4252 | the "pdump", because the objects' addresses may have changed, thus |
| 4253 | affecting their hash. */ | 4253 | affecting their hashes. */ |
| 4254 | void | 4254 | void |
| 4255 | hash_table_rehash (struct Lisp_Hash_Table *h) | 4255 | hash_table_rehash (Lisp_Object hash) |
| 4256 | { | 4256 | { |
| 4257 | ptrdiff_t size = HASH_TABLE_SIZE (h); | 4257 | struct Lisp_Hash_Table *h = XHASH_TABLE (hash); |
| 4258 | 4258 | ptrdiff_t i, count = h->count; | |
| 4259 | /* These structures may have been purecopied and shared | ||
| 4260 | (bug#36447). */ | ||
| 4261 | Lisp_Object hash = make_nil_vector (size); | ||
| 4262 | h->next = Fcopy_sequence (h->next); | ||
| 4263 | h->index = Fcopy_sequence (h->index); | ||
| 4264 | 4259 | ||
| 4265 | /* Recompute the actual hash codes for each entry in the table. | 4260 | /* Recompute the actual hash codes for each entry in the table. |
| 4266 | Order is still invalid. */ | 4261 | Order is still invalid. */ |
| 4267 | for (ptrdiff_t i = 0; i < size; ++i) | 4262 | for (i = 0; i < count; i++) |
| 4268 | { | 4263 | { |
| 4269 | Lisp_Object key = HASH_KEY (h, i); | 4264 | Lisp_Object key = HASH_KEY (h, i); |
| 4270 | if (!EQ (key, Qunbound)) | 4265 | Lisp_Object hash_code = h->test.hashfn (key, h); |
| 4271 | ASET (hash, i, h->test.hashfn (key, h)); | 4266 | ptrdiff_t start_of_bucket = XUFIXNUM (hash_code) % ASIZE (h->index); |
| 4267 | set_hash_hash_slot (h, i, hash_code); | ||
| 4268 | set_hash_next_slot (h, i, HASH_INDEX (h, start_of_bucket)); | ||
| 4269 | set_hash_index_slot (h, start_of_bucket, i); | ||
| 4270 | eassert (HASH_NEXT (h, i) != i); /* Stop loops. */ | ||
| 4272 | } | 4271 | } |
| 4273 | 4272 | ||
| 4274 | /* Reset the index so that any slot we don't fill below is marked | 4273 | ptrdiff_t size = ASIZE (h->next); |
| 4275 | invalid. */ | 4274 | for (; i + 1 < size; i++) |
| 4276 | Ffillarray (h->index, make_fixnum (-1)); | 4275 | set_hash_next_slot (h, i, i + 1); |
| 4277 | |||
| 4278 | /* Rebuild the collision chains. */ | ||
| 4279 | for (ptrdiff_t i = 0; i < size; ++i) | ||
| 4280 | if (!NILP (AREF (hash, i))) | ||
| 4281 | { | ||
| 4282 | EMACS_UINT hash_code = XUFIXNUM (AREF (hash, i)); | ||
| 4283 | ptrdiff_t start_of_bucket = hash_code % ASIZE (h->index); | ||
| 4284 | set_hash_next_slot (h, i, HASH_INDEX (h, start_of_bucket)); | ||
| 4285 | set_hash_index_slot (h, start_of_bucket, i); | ||
| 4286 | eassert (HASH_NEXT (h, i) != i); /* Stop loops. */ | ||
| 4287 | } | ||
| 4288 | |||
| 4289 | /* Finally, mark the hash table as having a valid hash order. | ||
| 4290 | Do this last so that if we're interrupted, we retry on next | ||
| 4291 | access. */ | ||
| 4292 | eassert (hash_rehash_needed_p (h)); | ||
| 4293 | h->hash = hash; | ||
| 4294 | eassert (!hash_rehash_needed_p (h)); | ||
| 4295 | } | 4276 | } |
| 4296 | 4277 | ||
| 4297 | /* Lookup KEY in hash table H. If HASH is non-null, return in *HASH | 4278 | /* Lookup KEY in hash table H. If HASH is non-null, return in *HASH |
| @@ -4303,8 +4284,6 @@ hash_lookup (struct Lisp_Hash_Table *h, Lisp_Object key, Lisp_Object *hash) | |||
| 4303 | { | 4284 | { |
| 4304 | ptrdiff_t start_of_bucket, i; | 4285 | ptrdiff_t start_of_bucket, i; |
| 4305 | 4286 | ||
| 4306 | hash_rehash_if_needed (h); | ||
| 4307 | |||
| 4308 | Lisp_Object hash_code = h->test.hashfn (key, h); | 4287 | Lisp_Object hash_code = h->test.hashfn (key, h); |
| 4309 | if (hash) | 4288 | if (hash) |
| 4310 | *hash = hash_code; | 4289 | *hash = hash_code; |
| @@ -4339,8 +4318,6 @@ hash_put (struct Lisp_Hash_Table *h, Lisp_Object key, Lisp_Object value, | |||
| 4339 | { | 4318 | { |
| 4340 | ptrdiff_t start_of_bucket, i; | 4319 | ptrdiff_t start_of_bucket, i; |
| 4341 | 4320 | ||
| 4342 | hash_rehash_if_needed (h); | ||
| 4343 | |||
| 4344 | /* Increment count after resizing because resizing may fail. */ | 4321 | /* Increment count after resizing because resizing may fail. */ |
| 4345 | maybe_resize_hash_table (h); | 4322 | maybe_resize_hash_table (h); |
| 4346 | h->count++; | 4323 | h->count++; |
| @@ -4373,8 +4350,6 @@ hash_remove_from_table (struct Lisp_Hash_Table *h, Lisp_Object key) | |||
| 4373 | ptrdiff_t start_of_bucket = XUFIXNUM (hash_code) % ASIZE (h->index); | 4350 | ptrdiff_t start_of_bucket = XUFIXNUM (hash_code) % ASIZE (h->index); |
| 4374 | ptrdiff_t prev = -1; | 4351 | ptrdiff_t prev = -1; |
| 4375 | 4352 | ||
| 4376 | hash_rehash_if_needed (h); | ||
| 4377 | |||
| 4378 | for (ptrdiff_t i = HASH_INDEX (h, start_of_bucket); | 4353 | for (ptrdiff_t i = HASH_INDEX (h, start_of_bucket); |
| 4379 | 0 <= i; | 4354 | 0 <= i; |
| 4380 | i = HASH_NEXT (h, i)) | 4355 | i = HASH_NEXT (h, i)) |
| @@ -4415,8 +4390,7 @@ hash_clear (struct Lisp_Hash_Table *h) | |||
| 4415 | if (h->count > 0) | 4390 | if (h->count > 0) |
| 4416 | { | 4391 | { |
| 4417 | ptrdiff_t size = HASH_TABLE_SIZE (h); | 4392 | ptrdiff_t size = HASH_TABLE_SIZE (h); |
| 4418 | if (!hash_rehash_needed_p (h)) | 4393 | memclear (xvector_contents (h->hash), size * word_size); |
| 4419 | memclear (xvector_contents (h->hash), size * word_size); | ||
| 4420 | for (ptrdiff_t i = 0; i < size; i++) | 4394 | for (ptrdiff_t i = 0; i < size; i++) |
| 4421 | { | 4395 | { |
| 4422 | set_hash_next_slot (h, i, i < size - 1 ? i + 1 : -1); | 4396 | set_hash_next_slot (h, i, i < size - 1 ? i + 1 : -1); |
| @@ -4452,9 +4426,7 @@ sweep_weak_table (struct Lisp_Hash_Table *h, bool remove_entries_p) | |||
| 4452 | for (ptrdiff_t bucket = 0; bucket < n; ++bucket) | 4426 | for (ptrdiff_t bucket = 0; bucket < n; ++bucket) |
| 4453 | { | 4427 | { |
| 4454 | /* Follow collision chain, removing entries that don't survive | 4428 | /* Follow collision chain, removing entries that don't survive |
| 4455 | this garbage collection. It's okay if hash_rehash_needed_p | 4429 | this garbage collection. */ |
| 4456 | (h) is true, since we're operating entirely on the cached | ||
| 4457 | hash values. */ | ||
| 4458 | ptrdiff_t prev = -1; | 4430 | ptrdiff_t prev = -1; |
| 4459 | ptrdiff_t next; | 4431 | ptrdiff_t next; |
| 4460 | for (ptrdiff_t i = HASH_INDEX (h, bucket); 0 <= i; i = next) | 4432 | for (ptrdiff_t i = HASH_INDEX (h, bucket); 0 <= i; i = next) |
| @@ -4499,7 +4471,7 @@ sweep_weak_table (struct Lisp_Hash_Table *h, bool remove_entries_p) | |||
| 4499 | set_hash_hash_slot (h, i, Qnil); | 4471 | set_hash_hash_slot (h, i, Qnil); |
| 4500 | 4472 | ||
| 4501 | eassert (h->count != 0); | 4473 | eassert (h->count != 0); |
| 4502 | h->count += h->count > 0 ? -1 : 1; | 4474 | h->count--; |
| 4503 | } | 4475 | } |
| 4504 | else | 4476 | else |
| 4505 | { | 4477 | { |
| @@ -4923,7 +4895,6 @@ DEFUN ("hash-table-count", Fhash_table_count, Shash_table_count, 1, 1, 0, | |||
| 4923 | (Lisp_Object table) | 4895 | (Lisp_Object table) |
| 4924 | { | 4896 | { |
| 4925 | struct Lisp_Hash_Table *h = check_hash_table (table); | 4897 | struct Lisp_Hash_Table *h = check_hash_table (table); |
| 4926 | eassert (h->count >= 0); | ||
| 4927 | return make_fixnum (h->count); | 4898 | return make_fixnum (h->count); |
| 4928 | } | 4899 | } |
| 4929 | 4900 | ||
diff --git a/src/json.c b/src/json.c index 814afc6d741..8c9583631ad 100644 --- a/src/json.c +++ b/src/json.c | |||
| @@ -479,9 +479,7 @@ lisp_to_json (Lisp_Object lisp, struct json_configuration *conf) | |||
| 479 | { | 479 | { |
| 480 | intmax_t low = TYPE_MINIMUM (json_int_t); | 480 | intmax_t low = TYPE_MINIMUM (json_int_t); |
| 481 | intmax_t high = TYPE_MAXIMUM (json_int_t); | 481 | intmax_t high = TYPE_MAXIMUM (json_int_t); |
| 482 | intmax_t value; | 482 | intmax_t value = check_integer_range (lisp, low, high); |
| 483 | if (! (integer_to_intmax (lisp, &value) && low <= value && value <= high)) | ||
| 484 | args_out_of_range_3 (lisp, make_int (low), make_int (high)); | ||
| 485 | return json_check (json_integer (value)); | 483 | return json_check (json_integer (value)); |
| 486 | } | 484 | } |
| 487 | else if (FLOATP (lisp)) | 485 | else if (FLOATP (lisp)) |
diff --git a/src/lisp.h b/src/lisp.h index 75ef6d30f97..5f913b72b45 100644 --- a/src/lisp.h +++ b/src/lisp.h | |||
| @@ -2286,11 +2286,7 @@ struct hash_table_test | |||
| 2286 | 2286 | ||
| 2287 | struct Lisp_Hash_Table | 2287 | struct Lisp_Hash_Table |
| 2288 | { | 2288 | { |
| 2289 | /* Change pdumper.c if you change the fields here. | 2289 | /* Change pdumper.c if you change the fields here. */ |
| 2290 | |||
| 2291 | IMPORTANT!!!!!!! | ||
| 2292 | |||
| 2293 | Call hash_rehash_if_needed() before accessing. */ | ||
| 2294 | 2290 | ||
| 2295 | /* This is for Lisp; the hash table code does not refer to it. */ | 2291 | /* This is for Lisp; the hash table code does not refer to it. */ |
| 2296 | union vectorlike_header header; | 2292 | union vectorlike_header header; |
| @@ -2409,20 +2405,7 @@ HASH_TABLE_SIZE (const struct Lisp_Hash_Table *h) | |||
| 2409 | return size; | 2405 | return size; |
| 2410 | } | 2406 | } |
| 2411 | 2407 | ||
| 2412 | void hash_table_rehash (struct Lisp_Hash_Table *h); | 2408 | void hash_table_rehash (Lisp_Object); |
| 2413 | |||
| 2414 | INLINE bool | ||
| 2415 | hash_rehash_needed_p (const struct Lisp_Hash_Table *h) | ||
| 2416 | { | ||
| 2417 | return NILP (h->hash); | ||
| 2418 | } | ||
| 2419 | |||
| 2420 | INLINE void | ||
| 2421 | hash_rehash_if_needed (struct Lisp_Hash_Table *h) | ||
| 2422 | { | ||
| 2423 | if (hash_rehash_needed_p (h)) | ||
| 2424 | hash_table_rehash (h); | ||
| 2425 | } | ||
| 2426 | 2409 | ||
| 2427 | /* Default size for hash tables if not specified. */ | 2410 | /* Default size for hash tables if not specified. */ |
| 2428 | 2411 | ||
| @@ -3975,7 +3958,8 @@ make_uninit_sub_char_table (int depth, int min_char) | |||
| 3975 | return v; | 3958 | return v; |
| 3976 | } | 3959 | } |
| 3977 | 3960 | ||
| 3978 | /* Make a vector of SIZE nils. */ | 3961 | /* Make a vector of SIZE nils - faster than make_vector (size, Qnil) |
| 3962 | if the OS already cleared the new memory. */ | ||
| 3979 | 3963 | ||
| 3980 | INLINE Lisp_Object | 3964 | INLINE Lisp_Object |
| 3981 | make_nil_vector (ptrdiff_t size) | 3965 | make_nil_vector (ptrdiff_t size) |
diff --git a/src/macfont.m b/src/macfont.m index 21bc7dde5b3..c7430d32772 100644 --- a/src/macfont.m +++ b/src/macfont.m | |||
| @@ -1120,7 +1120,10 @@ struct macfont_metrics | |||
| 1120 | glyph width. The `width_int' member is an integer that is | 1120 | glyph width. The `width_int' member is an integer that is |
| 1121 | closest to the width. The `width_frac' member is the fractional | 1121 | closest to the width. The `width_frac' member is the fractional |
| 1122 | adjustment representing a value in [-.5, .5], multiplied by | 1122 | adjustment representing a value in [-.5, .5], multiplied by |
| 1123 | WIDTH_FRAC_SCALE. For synthetic monospace fonts, they represent | 1123 | WIDTH_FRAC_SCALE. For monospace fonts, non-zero `width_frac' |
| 1124 | means `width_int' is further adjusted to a multiple of the | ||
| 1125 | (rounded) font width, and `width_frac' represents adjustment per | ||
| 1126 | unit character. For synthetic monospace fonts, they represent | ||
| 1124 | the advance delta for centering instead of the glyph width. */ | 1127 | the advance delta for centering instead of the glyph width. */ |
| 1125 | signed width_frac : WIDTH_FRAC_BITS, width_int : 16 - WIDTH_FRAC_BITS; | 1128 | signed width_frac : WIDTH_FRAC_BITS, width_int : 16 - WIDTH_FRAC_BITS; |
| 1126 | }; | 1129 | }; |
| @@ -1148,6 +1151,27 @@ enum metrics_status | |||
| 1148 | #define LCD_FONT_SMOOTHING_LEFT_MARGIN (0.396f) | 1151 | #define LCD_FONT_SMOOTHING_LEFT_MARGIN (0.396f) |
| 1149 | #define LCD_FONT_SMOOTHING_RIGHT_MARGIN (0.396f) | 1152 | #define LCD_FONT_SMOOTHING_RIGHT_MARGIN (0.396f) |
| 1150 | 1153 | ||
| 1154 | /* If FONT is monospace and WIDTH can be regarded as a multiple of its | ||
| 1155 | width where the multiplier is greater than 1, then return the | ||
| 1156 | multiplier. Otherwise return 0. */ | ||
| 1157 | static int | ||
| 1158 | macfont_monospace_width_multiplier (struct font *font, CGFloat width) | ||
| 1159 | { | ||
| 1160 | struct macfont_info *macfont_info = (struct macfont_info *) font; | ||
| 1161 | int multiplier = 0; | ||
| 1162 | |||
| 1163 | if (macfont_info->spacing == MACFONT_SPACING_MONO | ||
| 1164 | && font->space_width != 0) | ||
| 1165 | { | ||
| 1166 | multiplier = lround (width / font->space_width); | ||
| 1167 | if (multiplier == 1 | ||
| 1168 | || lround (width / multiplier) != font->space_width) | ||
| 1169 | multiplier = 0; | ||
| 1170 | } | ||
| 1171 | |||
| 1172 | return multiplier; | ||
| 1173 | } | ||
| 1174 | |||
| 1151 | static int | 1175 | static int |
| 1152 | macfont_glyph_extents (struct font *font, CGGlyph glyph, | 1176 | macfont_glyph_extents (struct font *font, CGGlyph glyph, |
| 1153 | struct font_metrics *metrics, CGFloat *advance_delta, | 1177 | struct font_metrics *metrics, CGFloat *advance_delta, |
| @@ -1192,13 +1216,38 @@ macfont_glyph_extents (struct font *font, CGGlyph glyph, | |||
| 1192 | else | 1216 | else |
| 1193 | fwidth = mac_font_get_advance_width_for_glyph (macfont, glyph); | 1217 | fwidth = mac_font_get_advance_width_for_glyph (macfont, glyph); |
| 1194 | 1218 | ||
| 1195 | /* For synthetic mono fonts, cache->width_{int,frac} holds the | 1219 | if (macfont_info->spacing == MACFONT_SPACING_MONO) |
| 1196 | advance delta value. */ | 1220 | { |
| 1197 | if (macfont_info->spacing == MACFONT_SPACING_SYNTHETIC_MONO) | 1221 | /* Some monospace fonts for programming languages contain |
| 1198 | fwidth = (font->pixel_size - fwidth) / 2; | 1222 | wider ligature glyphs consisting of multiple characters. |
| 1199 | cache->width_int = lround (fwidth); | 1223 | For such glyphs, simply rounding the combined fractional |
| 1200 | cache->width_frac = lround ((fwidth - cache->width_int) | 1224 | width to an integer can result in a value that is not a |
| 1201 | * WIDTH_FRAC_SCALE); | 1225 | multiple of the (rounded) font width. */ |
| 1226 | int multiplier = macfont_monospace_width_multiplier (font, fwidth); | ||
| 1227 | |||
| 1228 | if (multiplier) | ||
| 1229 | { | ||
| 1230 | cache->width_int = font->space_width * multiplier; | ||
| 1231 | cache->width_frac = lround ((fwidth / multiplier | ||
| 1232 | - font->space_width) | ||
| 1233 | * WIDTH_FRAC_SCALE); | ||
| 1234 | } | ||
| 1235 | else | ||
| 1236 | { | ||
| 1237 | cache->width_int = lround (fwidth); | ||
| 1238 | cache->width_frac = 0; | ||
| 1239 | } | ||
| 1240 | } | ||
| 1241 | else | ||
| 1242 | { | ||
| 1243 | /* For synthetic mono fonts, cache->width_{int,frac} holds | ||
| 1244 | the advance delta value. */ | ||
| 1245 | if (macfont_info->spacing == MACFONT_SPACING_SYNTHETIC_MONO) | ||
| 1246 | fwidth = (font->pixel_size - fwidth) / 2; | ||
| 1247 | cache->width_int = lround (fwidth); | ||
| 1248 | cache->width_frac = lround ((fwidth - cache->width_int) | ||
| 1249 | * WIDTH_FRAC_SCALE); | ||
| 1250 | } | ||
| 1202 | METRICS_SET_STATUS (cache, METRICS_WIDTH_VALID); | 1251 | METRICS_SET_STATUS (cache, METRICS_WIDTH_VALID); |
| 1203 | } | 1252 | } |
| 1204 | if (macfont_info->spacing == MACFONT_SPACING_SYNTHETIC_MONO) | 1253 | if (macfont_info->spacing == MACFONT_SPACING_SYNTHETIC_MONO) |
| @@ -1235,6 +1284,10 @@ macfont_glyph_extents (struct font *font, CGGlyph glyph, | |||
| 1235 | / (CGFloat) (WIDTH_FRAC_SCALE * 2)); | 1284 | / (CGFloat) (WIDTH_FRAC_SCALE * 2)); |
| 1236 | break; | 1285 | break; |
| 1237 | case MACFONT_SPACING_MONO: | 1286 | case MACFONT_SPACING_MONO: |
| 1287 | if (cache->width_frac) | ||
| 1288 | bounds.origin.x += - ((cache->width_frac | ||
| 1289 | / (CGFloat) (WIDTH_FRAC_SCALE * 2)) | ||
| 1290 | * (cache->width_int / font->space_width)); | ||
| 1238 | break; | 1291 | break; |
| 1239 | case MACFONT_SPACING_SYNTHETIC_MONO: | 1292 | case MACFONT_SPACING_SYNTHETIC_MONO: |
| 1240 | bounds.origin.x += (cache->width_int | 1293 | bounds.origin.x += (cache->width_int |
| @@ -1271,7 +1324,16 @@ macfont_glyph_extents (struct font *font, CGGlyph glyph, | |||
| 1271 | / (CGFloat) (WIDTH_FRAC_SCALE * 2))); | 1324 | / (CGFloat) (WIDTH_FRAC_SCALE * 2))); |
| 1272 | break; | 1325 | break; |
| 1273 | case MACFONT_SPACING_MONO: | 1326 | case MACFONT_SPACING_MONO: |
| 1274 | *advance_delta = 0; | 1327 | if (cache->width_frac) |
| 1328 | *advance_delta = 0; | ||
| 1329 | else | ||
| 1330 | { | ||
| 1331 | CGFloat delta = - ((cache->width_frac | ||
| 1332 | / (CGFloat) (WIDTH_FRAC_SCALE * 2)) | ||
| 1333 | * (cache->width_int / font->space_width)); | ||
| 1334 | |||
| 1335 | *advance_delta = (force_integral_p ? round (delta) : delta); | ||
| 1336 | } | ||
| 1275 | break; | 1337 | break; |
| 1276 | case MACFONT_SPACING_SYNTHETIC_MONO: | 1338 | case MACFONT_SPACING_SYNTHETIC_MONO: |
| 1277 | *advance_delta = (force_integral_p ? cache->width_int | 1339 | *advance_delta = (force_integral_p ? cache->width_int |
| @@ -3015,7 +3077,7 @@ macfont_shape (Lisp_Object lgstring, Lisp_Object direction) | |||
| 3015 | struct mac_glyph_layout *gl = glyph_layouts + i; | 3077 | struct mac_glyph_layout *gl = glyph_layouts + i; |
| 3016 | EMACS_INT from, to; | 3078 | EMACS_INT from, to; |
| 3017 | struct font_metrics metrics; | 3079 | struct font_metrics metrics; |
| 3018 | int xoff, yoff, wadjust; | 3080 | int xoff, yoff, wadjust, multiplier; |
| 3019 | 3081 | ||
| 3020 | if (NILP (lglyph)) | 3082 | if (NILP (lglyph)) |
| 3021 | { | 3083 | { |
| @@ -3068,7 +3130,11 @@ macfont_shape (Lisp_Object lgstring, Lisp_Object direction) | |||
| 3068 | 3130 | ||
| 3069 | xoff = lround (gl->advance_delta); | 3131 | xoff = lround (gl->advance_delta); |
| 3070 | yoff = lround (- gl->baseline_delta); | 3132 | yoff = lround (- gl->baseline_delta); |
| 3071 | wadjust = lround (gl->advance); | 3133 | multiplier = macfont_monospace_width_multiplier (font, gl->advance); |
| 3134 | if (multiplier) | ||
| 3135 | wadjust = font->space_width * multiplier; | ||
| 3136 | else | ||
| 3137 | wadjust = lround (gl->advance); | ||
| 3072 | if (xoff != 0 || yoff != 0 || wadjust != metrics.width) | 3138 | if (xoff != 0 || yoff != 0 || wadjust != metrics.width) |
| 3073 | { | 3139 | { |
| 3074 | Lisp_Object vec = make_uninit_vector (3); | 3140 | Lisp_Object vec = make_uninit_vector (3); |
diff --git a/src/minibuf.c b/src/minibuf.c index 9d870ce3640..cb302c5a605 100644 --- a/src/minibuf.c +++ b/src/minibuf.c | |||
| @@ -1212,9 +1212,6 @@ is used to further constrain the set of candidates. */) | |||
| 1212 | bucket = AREF (collection, idx); | 1212 | bucket = AREF (collection, idx); |
| 1213 | } | 1213 | } |
| 1214 | 1214 | ||
| 1215 | if (HASH_TABLE_P (collection)) | ||
| 1216 | hash_rehash_if_needed (XHASH_TABLE (collection)); | ||
| 1217 | |||
| 1218 | while (1) | 1215 | while (1) |
| 1219 | { | 1216 | { |
| 1220 | /* Get the next element of the alist, obarray, or hash-table. */ | 1217 | /* Get the next element of the alist, obarray, or hash-table. */ |
diff --git a/src/nsterm.m b/src/nsterm.m index 572b859a982..9f5916d78ed 100644 --- a/src/nsterm.m +++ b/src/nsterm.m | |||
| @@ -49,6 +49,7 @@ GNUstep port and post-20 update by Adrian Robert (arobert@cogsci.ucsd.edu) | |||
| 49 | #include "nsterm.h" | 49 | #include "nsterm.h" |
| 50 | #include "systime.h" | 50 | #include "systime.h" |
| 51 | #include "character.h" | 51 | #include "character.h" |
| 52 | #include "xwidget.h" | ||
| 52 | #include "fontset.h" | 53 | #include "fontset.h" |
| 53 | #include "composite.h" | 54 | #include "composite.h" |
| 54 | #include "ccl.h" | 55 | #include "ccl.h" |
| @@ -2600,7 +2601,8 @@ frame_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y) | |||
| 2600 | } | 2601 | } |
| 2601 | 2602 | ||
| 2602 | static int | 2603 | static int |
| 2603 | ns_note_mouse_movement (struct frame *frame, CGFloat x, CGFloat y) | 2604 | ns_note_mouse_movement (struct frame *frame, CGFloat x, CGFloat y, |
| 2605 | BOOL dragging) | ||
| 2604 | /* ------------------------------------------------------------------------ | 2606 | /* ------------------------------------------------------------------------ |
| 2605 | Called by EmacsView on mouseMovement events. Passes on | 2607 | Called by EmacsView on mouseMovement events. Passes on |
| 2606 | to emacs mainstream code if we moved off of a rect of interest | 2608 | to emacs mainstream code if we moved off of a rect of interest |
| @@ -2609,17 +2611,24 @@ ns_note_mouse_movement (struct frame *frame, CGFloat x, CGFloat y) | |||
| 2609 | { | 2611 | { |
| 2610 | struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame); | 2612 | struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame); |
| 2611 | NSRect *r; | 2613 | NSRect *r; |
| 2614 | BOOL force_update = NO; | ||
| 2612 | 2615 | ||
| 2613 | // NSTRACE ("note_mouse_movement"); | 2616 | // NSTRACE ("note_mouse_movement"); |
| 2614 | 2617 | ||
| 2615 | dpyinfo->last_mouse_motion_frame = frame; | 2618 | dpyinfo->last_mouse_motion_frame = frame; |
| 2616 | r = &dpyinfo->last_mouse_glyph; | 2619 | r = &dpyinfo->last_mouse_glyph; |
| 2617 | 2620 | ||
| 2621 | /* If the last rect is too large (ex, xwidget webkit), update at | ||
| 2622 | every move, or resizing by dragging modeline or vertical split is | ||
| 2623 | very hard to make its way. */ | ||
| 2624 | if (dragging && (r->size.width > 32 || r->size.height > 32)) | ||
| 2625 | force_update = YES; | ||
| 2626 | |||
| 2618 | /* Note, this doesn't get called for enter/leave, since we don't have a | 2627 | /* Note, this doesn't get called for enter/leave, since we don't have a |
| 2619 | position. Those are taken care of in the corresponding NSView methods. */ | 2628 | position. Those are taken care of in the corresponding NSView methods. */ |
| 2620 | 2629 | ||
| 2621 | /* Has movement gone beyond last rect we were tracking? */ | 2630 | /* Has movement gone beyond last rect we were tracking? */ |
| 2622 | if (x < r->origin.x || x >= r->origin.x + r->size.width | 2631 | if (force_update || x < r->origin.x || x >= r->origin.x + r->size.width |
| 2623 | || y < r->origin.y || y >= r->origin.y + r->size.height) | 2632 | || y < r->origin.y || y >= r->origin.y + r->size.height) |
| 2624 | { | 2633 | { |
| 2625 | ns_update_begin (frame); | 2634 | ns_update_begin (frame); |
| @@ -4368,6 +4377,10 @@ ns_draw_glyph_string (struct glyph_string *s) | |||
| 4368 | ns_unfocus (s->f); | 4377 | ns_unfocus (s->f); |
| 4369 | break; | 4378 | break; |
| 4370 | 4379 | ||
| 4380 | case XWIDGET_GLYPH: | ||
| 4381 | x_draw_xwidget_glyph_string (s); | ||
| 4382 | break; | ||
| 4383 | |||
| 4371 | case STRETCH_GLYPH: | 4384 | case STRETCH_GLYPH: |
| 4372 | ns_dumpglyphs_stretch (s); | 4385 | ns_dumpglyphs_stretch (s); |
| 4373 | break; | 4386 | break; |
| @@ -7065,6 +7078,7 @@ not_in_argv (NSString *arg) | |||
| 7065 | struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe); | 7078 | struct ns_display_info *dpyinfo = FRAME_DISPLAY_INFO (emacsframe); |
| 7066 | Lisp_Object frame; | 7079 | Lisp_Object frame; |
| 7067 | NSPoint pt; | 7080 | NSPoint pt; |
| 7081 | BOOL dragging; | ||
| 7068 | 7082 | ||
| 7069 | NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "[EmacsView mouseMoved:]"); | 7083 | NSTRACE_WHEN (NSTRACE_GROUP_EVENTS, "[EmacsView mouseMoved:]"); |
| 7070 | 7084 | ||
| @@ -7107,7 +7121,8 @@ not_in_argv (NSString *arg) | |||
| 7107 | last_mouse_window = window; | 7121 | last_mouse_window = window; |
| 7108 | } | 7122 | } |
| 7109 | 7123 | ||
| 7110 | if (!ns_note_mouse_movement (emacsframe, pt.x, pt.y)) | 7124 | dragging = (e.type == NSEventTypeLeftMouseDragged); |
| 7125 | if (!ns_note_mouse_movement (emacsframe, pt.x, pt.y, dragging)) | ||
| 7111 | help_echo_string = previous_help_echo_string; | 7126 | help_echo_string = previous_help_echo_string; |
| 7112 | 7127 | ||
| 7113 | XSETFRAME (frame, emacsframe); | 7128 | XSETFRAME (frame, emacsframe); |
diff --git a/src/nsxwidget.h b/src/nsxwidget.h new file mode 100644 index 00000000000..3d91594c341 --- /dev/null +++ b/src/nsxwidget.h | |||
| @@ -0,0 +1,80 @@ | |||
| 1 | /* Header for NS Cocoa part of xwidget and webkit widget. | ||
| 2 | |||
| 3 | Copyright (C) 2019-2020 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 <http://www.gnu.org/licenses/>. */ | ||
| 19 | |||
| 20 | #ifndef NSXWIDGET_H_INCLUDED | ||
| 21 | #define NSXWIDGET_H_INCLUDED | ||
| 22 | |||
| 23 | /* This file can be included from non-objc files through 'xwidget.h'. */ | ||
| 24 | #ifdef __OBJC__ | ||
| 25 | #import <AppKit/NSView.h> | ||
| 26 | #endif | ||
| 27 | |||
| 28 | #include "dispextern.h" | ||
| 29 | #include "lisp.h" | ||
| 30 | #include "xwidget.h" | ||
| 31 | |||
| 32 | /* Functions for xwidget webkit. */ | ||
| 33 | |||
| 34 | bool nsxwidget_is_web_view (struct xwidget *xw); | ||
| 35 | Lisp_Object nsxwidget_webkit_uri (struct xwidget *xw); | ||
| 36 | Lisp_Object nsxwidget_webkit_title (struct xwidget *xw); | ||
| 37 | void nsxwidget_webkit_goto_uri (struct xwidget *xw, const char *uri); | ||
| 38 | void nsxwidget_webkit_goto_history (struct xwidget *xw, int rel_pos); | ||
| 39 | void nsxwidget_webkit_zoom (struct xwidget *xw, double zoom_change); | ||
| 40 | void nsxwidget_webkit_execute_script (struct xwidget *xw, const char *script, | ||
| 41 | Lisp_Object fun); | ||
| 42 | |||
| 43 | /* Functions for xwidget model. */ | ||
| 44 | |||
| 45 | #ifdef __OBJC__ | ||
| 46 | @interface XwWindow : NSView | ||
| 47 | @property struct xwidget *xw; | ||
| 48 | @end | ||
| 49 | #endif | ||
| 50 | |||
| 51 | void nsxwidget_init (struct xwidget *xw); | ||
| 52 | void nsxwidget_kill (struct xwidget *xw); | ||
| 53 | void nsxwidget_resize (struct xwidget *xw); | ||
| 54 | Lisp_Object nsxwidget_get_size (struct xwidget *xw); | ||
| 55 | |||
| 56 | /* Functions for xwidget view. */ | ||
| 57 | |||
| 58 | #ifdef __OBJC__ | ||
| 59 | @interface XvWindow : NSView | ||
| 60 | @property struct xwidget *xw; | ||
| 61 | @property struct xwidget_view *xv; | ||
| 62 | @end | ||
| 63 | #endif | ||
| 64 | |||
| 65 | void nsxwidget_init_view (struct xwidget_view *xv, | ||
| 66 | struct xwidget *xww, | ||
| 67 | struct glyph_string *s, | ||
| 68 | int x, int y); | ||
| 69 | void nsxwidget_delete_view (struct xwidget_view *xv); | ||
| 70 | |||
| 71 | void nsxwidget_show_view (struct xwidget_view *xv); | ||
| 72 | void nsxwidget_hide_view (struct xwidget_view *xv); | ||
| 73 | void nsxwidget_resize_view (struct xwidget_view *xv, | ||
| 74 | int widget, int height); | ||
| 75 | |||
| 76 | void nsxwidget_move_view (struct xwidget_view *xv, int x, int y); | ||
| 77 | void nsxwidget_move_widget_in_view (struct xwidget_view *xv, int x, int y); | ||
| 78 | void nsxwidget_set_needsdisplay (struct xwidget_view *xv); | ||
| 79 | |||
| 80 | #endif /* NSXWIDGET_H_INCLUDED */ | ||
diff --git a/src/nsxwidget.m b/src/nsxwidget.m new file mode 100644 index 00000000000..370abee395c --- /dev/null +++ b/src/nsxwidget.m | |||
| @@ -0,0 +1,601 @@ | |||
| 1 | /* NS Cocoa part implementation of xwidget and webkit widget. | ||
| 2 | |||
| 3 | Copyright (C) 2019-2020 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 <http://www.gnu.org/licenses/>. */ | ||
| 19 | |||
| 20 | #include <config.h> | ||
| 21 | |||
| 22 | #include "lisp.h" | ||
| 23 | #include "blockinput.h" | ||
| 24 | #include "dispextern.h" | ||
| 25 | #include "buffer.h" | ||
| 26 | #include "frame.h" | ||
| 27 | #include "nsterm.h" | ||
| 28 | #include "xwidget.h" | ||
| 29 | |||
| 30 | #import <AppKit/AppKit.h> | ||
| 31 | #import <WebKit/WebKit.h> | ||
| 32 | |||
| 33 | /* Thoughts on NS Cocoa xwidget and webkit2: | ||
| 34 | |||
| 35 | Webkit2 process architecture seems to be very hostile for offscreen | ||
| 36 | rendering techniques, which is used by GTK xwiget implementation; | ||
| 37 | Specifically NSView level view sharing / copying is not working. | ||
| 38 | |||
| 39 | *** So only one view can be associcated with a model. *** | ||
| 40 | |||
| 41 | With this decision, implementation is plain and can expect best out | ||
| 42 | of webkit2's rationale. But process and session structures will | ||
| 43 | diverge from GTK xwiget. Though, cosmetically similar usages can | ||
| 44 | be presented and will be preferred, if agreeable. | ||
| 45 | |||
| 46 | For other widget types, OSR seems possible, but will not care for a | ||
| 47 | while. */ | ||
| 48 | |||
| 49 | /* Xwidget webkit. */ | ||
| 50 | |||
| 51 | @interface XwWebView : WKWebView | ||
| 52 | <WKNavigationDelegate, WKUIDelegate, WKScriptMessageHandler> | ||
| 53 | @property struct xwidget *xw; | ||
| 54 | /* Map url to whether javascript is blocked by | ||
| 55 | 'Content-Security-Policy' sandbox without allow-scripts. */ | ||
| 56 | @property(retain) NSMutableDictionary *urlScriptBlocked; | ||
| 57 | @end | ||
| 58 | @implementation XwWebView : WKWebView | ||
| 59 | |||
| 60 | - (id)initWithFrame:(CGRect)frame | ||
| 61 | configuration:(WKWebViewConfiguration *)configuration | ||
| 62 | xwidget:(struct xwidget *)xw | ||
| 63 | { | ||
| 64 | /* Script controller to add script message handler and user script. */ | ||
| 65 | WKUserContentController *scriptor = [[WKUserContentController alloc] init]; | ||
| 66 | configuration.userContentController = scriptor; | ||
| 67 | |||
| 68 | /* Enable inspect element context menu item for debugging. */ | ||
| 69 | [configuration.preferences setValue:@YES | ||
| 70 | forKey:@"developerExtrasEnabled"]; | ||
| 71 | |||
| 72 | Lisp_Object enablePlugins = | ||
| 73 | Fintern (build_string ("xwidget-webkit-enable-plugins"), Qnil); | ||
| 74 | if (!EQ (Fsymbol_value (enablePlugins), Qnil)) | ||
| 75 | configuration.preferences.plugInsEnabled = YES; | ||
| 76 | |||
| 77 | self = [super initWithFrame:frame configuration:configuration]; | ||
| 78 | if (self) | ||
| 79 | { | ||
| 80 | self.xw = xw; | ||
| 81 | self.urlScriptBlocked = [[NSMutableDictionary alloc] init]; | ||
| 82 | self.navigationDelegate = self; | ||
| 83 | self.UIDelegate = self; | ||
| 84 | self.customUserAgent = | ||
| 85 | @"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6)" | ||
| 86 | @" AppleWebKit/603.3.8 (KHTML, like Gecko)" | ||
| 87 | @" Version/11.0.1 Safari/603.3.8"; | ||
| 88 | [scriptor addScriptMessageHandler:self name:@"keyDown"]; | ||
| 89 | [scriptor addUserScript:[[WKUserScript alloc] | ||
| 90 | initWithSource:xwScript | ||
| 91 | injectionTime: | ||
| 92 | WKUserScriptInjectionTimeAtDocumentStart | ||
| 93 | forMainFrameOnly:NO]]; | ||
| 94 | } | ||
| 95 | return self; | ||
| 96 | } | ||
| 97 | |||
| 98 | - (void)webView:(WKWebView *)webView | ||
| 99 | didFinishNavigation:(WKNavigation *)navigation | ||
| 100 | { | ||
| 101 | if (EQ (Fbuffer_live_p (self.xw->buffer), Qt)) | ||
| 102 | store_xwidget_event_string (self.xw, "load-changed", ""); | ||
| 103 | } | ||
| 104 | |||
| 105 | - (void)webView:(WKWebView *)webView | ||
| 106 | decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction | ||
| 107 | decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler | ||
| 108 | { | ||
| 109 | switch (navigationAction.navigationType) { | ||
| 110 | case WKNavigationTypeLinkActivated: | ||
| 111 | decisionHandler (WKNavigationActionPolicyAllow); | ||
| 112 | break; | ||
| 113 | default: | ||
| 114 | // decisionHandler (WKNavigationActionPolicyCancel); | ||
| 115 | decisionHandler (WKNavigationActionPolicyAllow); | ||
| 116 | break; | ||
| 117 | } | ||
| 118 | } | ||
| 119 | |||
| 120 | - (void)webView:(WKWebView *)webView | ||
| 121 | decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse | ||
| 122 | decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler | ||
| 123 | { | ||
| 124 | if (!navigationResponse.canShowMIMEType) | ||
| 125 | { | ||
| 126 | NSString *url = navigationResponse.response.URL.absoluteString; | ||
| 127 | NSString *mimetype = navigationResponse.response.MIMEType; | ||
| 128 | NSString *filename = navigationResponse.response.suggestedFilename; | ||
| 129 | decisionHandler (WKNavigationResponsePolicyCancel); | ||
| 130 | store_xwidget_download_callback_event (self.xw, | ||
| 131 | url.UTF8String, | ||
| 132 | mimetype.UTF8String, | ||
| 133 | filename.UTF8String); | ||
| 134 | return; | ||
| 135 | } | ||
| 136 | decisionHandler (WKNavigationResponsePolicyAllow); | ||
| 137 | |||
| 138 | self.urlScriptBlocked[navigationResponse.response.URL] = | ||
| 139 | [NSNumber numberWithBool:NO]; | ||
| 140 | if ([navigationResponse.response isKindOfClass:[NSHTTPURLResponse class]]) | ||
| 141 | { | ||
| 142 | NSDictionary *headers = | ||
| 143 | ((NSHTTPURLResponse *) navigationResponse.response).allHeaderFields; | ||
| 144 | NSString *value = headers[@"Content-Security-Policy"]; | ||
| 145 | if (value) | ||
| 146 | { | ||
| 147 | /* TODO: Sloppy parsing of 'Content-Security-Policy' value. */ | ||
| 148 | NSRange sandbox = [value rangeOfString:@"sandbox"]; | ||
| 149 | if (sandbox.location != NSNotFound | ||
| 150 | && (sandbox.location == 0 | ||
| 151 | || [value characterAtIndex:(sandbox.location - 1)] == ' ' | ||
| 152 | || [value characterAtIndex:(sandbox.location - 1)] == ';')) | ||
| 153 | { | ||
| 154 | NSRange allowScripts = [value rangeOfString:@"allow-scripts"]; | ||
| 155 | if (allowScripts.location == NSNotFound | ||
| 156 | || allowScripts.location < sandbox.location) | ||
| 157 | self.urlScriptBlocked[navigationResponse.response.URL] = | ||
| 158 | [NSNumber numberWithBool:YES]; | ||
| 159 | } | ||
| 160 | } | ||
| 161 | } | ||
| 162 | } | ||
| 163 | |||
| 164 | /* No additional new webview or emacs window will be created | ||
| 165 | for <a ... target="_blank">. */ | ||
| 166 | - (WKWebView *)webView:(WKWebView *)webView | ||
| 167 | createWebViewWithConfiguration:(WKWebViewConfiguration *)configuration | ||
| 168 | forNavigationAction:(WKNavigationAction *)navigationAction | ||
| 169 | windowFeatures:(WKWindowFeatures *)windowFeatures | ||
| 170 | { | ||
| 171 | if (!navigationAction.targetFrame.isMainFrame) | ||
| 172 | [webView loadRequest:navigationAction.request]; | ||
| 173 | return nil; | ||
| 174 | } | ||
| 175 | |||
| 176 | /* Open panel for file upload. */ | ||
| 177 | - (void)webView:(WKWebView *)webView | ||
| 178 | runOpenPanelWithParameters:(WKOpenPanelParameters *)parameters | ||
| 179 | initiatedByFrame:(WKFrameInfo *)frame | ||
| 180 | completionHandler:(void (^)(NSArray<NSURL *> *URLs))completionHandler | ||
| 181 | { | ||
| 182 | NSOpenPanel *openPanel = [NSOpenPanel openPanel]; | ||
| 183 | openPanel.canChooseFiles = YES; | ||
| 184 | openPanel.canChooseDirectories = NO; | ||
| 185 | openPanel.allowsMultipleSelection = parameters.allowsMultipleSelection; | ||
| 186 | if ([openPanel runModal] == NSModalResponseOK) | ||
| 187 | completionHandler (openPanel.URLs); | ||
| 188 | else | ||
| 189 | completionHandler (nil); | ||
| 190 | } | ||
| 191 | |||
| 192 | /* By forwarding mouse events to emacs view (frame) | ||
| 193 | - Mouse click in webview selects the window contains the webview. | ||
| 194 | - Correct mouse hand/arrow/I-beam is displayed (TODO: not perfect yet). | ||
| 195 | */ | ||
| 196 | |||
| 197 | - (void)mouseDown:(NSEvent *)event | ||
| 198 | { | ||
| 199 | [self.xw->xv->emacswindow mouseDown:event]; | ||
| 200 | [super mouseDown:event]; | ||
| 201 | } | ||
| 202 | |||
| 203 | - (void)mouseUp:(NSEvent *)event | ||
| 204 | { | ||
| 205 | [self.xw->xv->emacswindow mouseUp:event]; | ||
| 206 | [super mouseUp:event]; | ||
| 207 | } | ||
| 208 | |||
| 209 | /* Basically we want keyboard events handled by emacs unless an input | ||
| 210 | element has focus. Especially, while incremental search, we set | ||
| 211 | emacs as first responder to avoid focus held in an input element | ||
| 212 | with matching text. */ | ||
| 213 | |||
| 214 | - (void)keyDown:(NSEvent *)event | ||
| 215 | { | ||
| 216 | Lisp_Object var = Fintern (build_string ("isearch-mode"), Qnil); | ||
| 217 | Lisp_Object val = buffer_local_value (var, Fcurrent_buffer ()); | ||
| 218 | if (!EQ (val, Qunbound) && !EQ (val, Qnil)) | ||
| 219 | { | ||
| 220 | [self.window makeFirstResponder:self.xw->xv->emacswindow]; | ||
| 221 | [self.xw->xv->emacswindow keyDown:event]; | ||
| 222 | return; | ||
| 223 | } | ||
| 224 | |||
| 225 | /* Emacs handles keyboard events when javascript is blocked. */ | ||
| 226 | if ([self.urlScriptBlocked[self.URL] boolValue]) | ||
| 227 | { | ||
| 228 | [self.xw->xv->emacswindow keyDown:event]; | ||
| 229 | return; | ||
| 230 | } | ||
| 231 | |||
| 232 | [self evaluateJavaScript:@"xwHasFocus()" | ||
| 233 | completionHandler:^(id result, NSError *error) { | ||
| 234 | if (error) | ||
| 235 | { | ||
| 236 | NSLog (@"xwHasFocus: %@", error); | ||
| 237 | [self.xw->xv->emacswindow keyDown:event]; | ||
| 238 | } | ||
| 239 | else if (result) | ||
| 240 | { | ||
| 241 | NSNumber *hasFocus = result; /* __NSCFBoolean */ | ||
| 242 | if (!hasFocus.boolValue) | ||
| 243 | [self.xw->xv->emacswindow keyDown:event]; | ||
| 244 | else | ||
| 245 | [super keyDown:event]; | ||
| 246 | } | ||
| 247 | }]; | ||
| 248 | } | ||
| 249 | |||
| 250 | - (void)interpretKeyEvents:(NSArray<NSEvent *> *)eventArray | ||
| 251 | { | ||
| 252 | /* We should do nothing and do not forward (default implementation | ||
| 253 | if we not override here) to let emacs collect key events and ask | ||
| 254 | interpretKeyEvents to its superclass. */ | ||
| 255 | } | ||
| 256 | |||
| 257 | static NSString *xwScript; | ||
| 258 | + (void)initialize | ||
| 259 | { | ||
| 260 | /* Find out if an input element has focus. | ||
| 261 | Message to script message handler when 'C-g' key down. */ | ||
| 262 | if (!xwScript) | ||
| 263 | xwScript = | ||
| 264 | @"function xwHasFocus() {" | ||
| 265 | @" var ae = document.activeElement;" | ||
| 266 | @" if (ae) {" | ||
| 267 | @" var name = ae.nodeName;" | ||
| 268 | @" return name == 'INPUT' || name == 'TEXTAREA';" | ||
| 269 | @" } else {" | ||
| 270 | @" return false;" | ||
| 271 | @" }" | ||
| 272 | @"}" | ||
| 273 | @"function xwKeyDown(event) {" | ||
| 274 | @" if (event.ctrlKey && event.key == 'g') {" | ||
| 275 | @" window.webkit.messageHandlers.keyDown.postMessage('C-g');" | ||
| 276 | @" }" | ||
| 277 | @"}" | ||
| 278 | @"document.addEventListener('keydown', xwKeyDown);" | ||
| 279 | ; | ||
| 280 | } | ||
| 281 | |||
| 282 | /* Confirming to WKScriptMessageHandler, listens concerning keyDown in | ||
| 283 | webkit. Currently 'C-g'. */ | ||
| 284 | - (void)userContentController:(WKUserContentController *)userContentController | ||
| 285 | didReceiveScriptMessage:(WKScriptMessage *)message | ||
| 286 | { | ||
| 287 | if ([message.body isEqualToString:@"C-g"]) | ||
| 288 | { | ||
| 289 | /* Just give up focus, no relay "C-g" to emacs, another "C-g" | ||
| 290 | follows will be handled by emacs. */ | ||
| 291 | [self.window makeFirstResponder:self.xw->xv->emacswindow]; | ||
| 292 | } | ||
| 293 | } | ||
| 294 | |||
| 295 | @end | ||
| 296 | |||
| 297 | /* Xwidget webkit commands. */ | ||
| 298 | |||
| 299 | static Lisp_Object build_string_with_nsstr (NSString *nsstr); | ||
| 300 | |||
| 301 | bool | ||
| 302 | nsxwidget_is_web_view (struct xwidget *xw) | ||
| 303 | { | ||
| 304 | return xw->xwWidget != NULL && | ||
| 305 | [xw->xwWidget isKindOfClass:WKWebView.class]; | ||
| 306 | } | ||
| 307 | |||
| 308 | Lisp_Object | ||
| 309 | nsxwidget_webkit_uri (struct xwidget *xw) | ||
| 310 | { | ||
| 311 | XwWebView *xwWebView = (XwWebView *) xw->xwWidget; | ||
| 312 | return build_string_with_nsstr (xwWebView.URL.absoluteString); | ||
| 313 | } | ||
| 314 | |||
| 315 | Lisp_Object | ||
| 316 | nsxwidget_webkit_title (struct xwidget *xw) | ||
| 317 | { | ||
| 318 | XwWebView *xwWebView = (XwWebView *) xw->xwWidget; | ||
| 319 | return build_string_with_nsstr (xwWebView.title); | ||
| 320 | } | ||
| 321 | |||
| 322 | /* @Note ATS - Need application transport security in 'Info.plist' or | ||
| 323 | remote pages will not loaded. */ | ||
| 324 | void | ||
| 325 | nsxwidget_webkit_goto_uri (struct xwidget *xw, const char *uri) | ||
| 326 | { | ||
| 327 | XwWebView *xwWebView = (XwWebView *) xw->xwWidget; | ||
| 328 | NSString *urlString = [NSString stringWithUTF8String:uri]; | ||
| 329 | NSURL *url = [NSURL URLWithString:urlString]; | ||
| 330 | NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url]; | ||
| 331 | [xwWebView loadRequest:urlRequest]; | ||
| 332 | } | ||
| 333 | |||
| 334 | void | ||
| 335 | nsxwidget_webkit_goto_history (struct xwidget *xw, int rel_pos) | ||
| 336 | { | ||
| 337 | XwWebView *xwWebView = (XwWebView *) xw->xwWidget; | ||
| 338 | switch (rel_pos) { | ||
| 339 | case -1: [xwWebView goBack]; break; | ||
| 340 | case 0: [xwWebView reload]; break; | ||
| 341 | case 1: [xwWebView goForward]; break; | ||
| 342 | } | ||
| 343 | } | ||
| 344 | |||
| 345 | void | ||
| 346 | nsxwidget_webkit_zoom (struct xwidget *xw, double zoom_change) | ||
| 347 | { | ||
| 348 | XwWebView *xwWebView = (XwWebView *) xw->xwWidget; | ||
| 349 | xwWebView.magnification += zoom_change; | ||
| 350 | /* TODO: setMagnification:centeredAtPoint. */ | ||
| 351 | } | ||
| 352 | |||
| 353 | /* Build lisp string */ | ||
| 354 | static Lisp_Object | ||
| 355 | build_string_with_nsstr (NSString *nsstr) | ||
| 356 | { | ||
| 357 | const char *utfstr = [nsstr UTF8String]; | ||
| 358 | NSUInteger bytes = [nsstr lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; | ||
| 359 | return make_string (utfstr, bytes); | ||
| 360 | } | ||
| 361 | |||
| 362 | /* Recursively convert an objc native type JavaScript value to a Lisp | ||
| 363 | value. Mostly copied from GTK xwidget 'webkit_js_to_lisp'. */ | ||
| 364 | static Lisp_Object | ||
| 365 | js_to_lisp (id value) | ||
| 366 | { | ||
| 367 | if (value == nil || [value isKindOfClass:NSNull.class]) | ||
| 368 | return Qnil; | ||
| 369 | else if ([value isKindOfClass:NSString.class]) | ||
| 370 | return build_string_with_nsstr ((NSString *) value); | ||
| 371 | else if ([value isKindOfClass:NSNumber.class]) | ||
| 372 | { | ||
| 373 | NSNumber *nsnum = (NSNumber *) value; | ||
| 374 | char type = nsnum.objCType[0]; | ||
| 375 | if (type == 'c') /* __NSCFBoolean has type character 'c'. */ | ||
| 376 | return nsnum.boolValue? Qt : Qnil; | ||
| 377 | else | ||
| 378 | { | ||
| 379 | if (type == 'i' || type == 'l') | ||
| 380 | return make_int (nsnum.longValue); | ||
| 381 | else if (type == 'f' || type == 'd') | ||
| 382 | return make_float (nsnum.doubleValue); | ||
| 383 | /* else fall through. */ | ||
| 384 | } | ||
| 385 | } | ||
| 386 | else if ([value isKindOfClass:NSArray.class]) | ||
| 387 | { | ||
| 388 | NSArray *nsarr = (NSArray *) value; | ||
| 389 | EMACS_INT n = nsarr.count; | ||
| 390 | Lisp_Object obj; | ||
| 391 | struct Lisp_Vector *p = allocate_vector (n); | ||
| 392 | |||
| 393 | for (ptrdiff_t i = 0; i < n; ++i) | ||
| 394 | p->contents[i] = js_to_lisp ([nsarr objectAtIndex:i]); | ||
| 395 | XSETVECTOR (obj, p); | ||
| 396 | return obj; | ||
| 397 | } | ||
| 398 | else if ([value isKindOfClass:NSDictionary.class]) | ||
| 399 | { | ||
| 400 | NSDictionary *nsdict = (NSDictionary *) value; | ||
| 401 | NSArray *keys = nsdict.allKeys; | ||
| 402 | ptrdiff_t n = keys.count; | ||
| 403 | Lisp_Object obj; | ||
| 404 | struct Lisp_Vector *p = allocate_vector (n); | ||
| 405 | |||
| 406 | for (ptrdiff_t i = 0; i < n; ++i) | ||
| 407 | { | ||
| 408 | NSString *prop_key = (NSString *) [keys objectAtIndex:i]; | ||
| 409 | id prop_value = [nsdict valueForKey:prop_key]; | ||
| 410 | p->contents[i] = Fcons (build_string_with_nsstr (prop_key), | ||
| 411 | js_to_lisp (prop_value)); | ||
| 412 | } | ||
| 413 | XSETVECTOR (obj, p); | ||
| 414 | return obj; | ||
| 415 | } | ||
| 416 | NSLog (@"Unhandled type in javascript result"); | ||
| 417 | return Qnil; | ||
| 418 | } | ||
| 419 | |||
| 420 | void | ||
| 421 | nsxwidget_webkit_execute_script (struct xwidget *xw, const char *script, | ||
| 422 | Lisp_Object fun) | ||
| 423 | { | ||
| 424 | XwWebView *xwWebView = (XwWebView *) xw->xwWidget; | ||
| 425 | if ([xwWebView.urlScriptBlocked[xwWebView.URL] boolValue]) | ||
| 426 | { | ||
| 427 | message ("Javascript is blocked by 'CSP: sandbox'."); | ||
| 428 | return; | ||
| 429 | } | ||
| 430 | |||
| 431 | NSString *javascriptString = [NSString stringWithUTF8String:script]; | ||
| 432 | [xwWebView evaluateJavaScript:javascriptString | ||
| 433 | completionHandler:^(id result, NSError *error) { | ||
| 434 | if (error) | ||
| 435 | { | ||
| 436 | NSLog (@"evaluateJavaScript error : %@", error.localizedDescription); | ||
| 437 | NSLog (@"error script=%@", javascriptString); | ||
| 438 | } | ||
| 439 | else if (result && FUNCTIONP (fun)) | ||
| 440 | { | ||
| 441 | // NSLog (@"result=%@, type=%@", result, [result class]); | ||
| 442 | Lisp_Object lisp_value = js_to_lisp (result); | ||
| 443 | store_xwidget_js_callback_event (xw, fun, lisp_value); | ||
| 444 | } | ||
| 445 | }]; | ||
| 446 | } | ||
| 447 | |||
| 448 | /* Window containing an xwidget. */ | ||
| 449 | |||
| 450 | @implementation XwWindow | ||
| 451 | - (BOOL)isFlipped { return YES; } | ||
| 452 | @end | ||
| 453 | |||
| 454 | /* Xwidget model, macOS Cocoa part. */ | ||
| 455 | |||
| 456 | void | ||
| 457 | nsxwidget_init(struct xwidget *xw) | ||
| 458 | { | ||
| 459 | block_input (); | ||
| 460 | NSRect rect = NSMakeRect (0, 0, xw->width, xw->height); | ||
| 461 | xw->xwWidget = [[XwWebView alloc] | ||
| 462 | initWithFrame:rect | ||
| 463 | configuration:[[WKWebViewConfiguration alloc] init] | ||
| 464 | xwidget:xw]; | ||
| 465 | xw->xwWindow = [[XwWindow alloc] | ||
| 466 | initWithFrame:rect]; | ||
| 467 | [xw->xwWindow addSubview:xw->xwWidget]; | ||
| 468 | xw->xv = NULL; /* for 1 to 1 relationship of webkit2. */ | ||
| 469 | unblock_input (); | ||
| 470 | } | ||
| 471 | |||
| 472 | void | ||
| 473 | nsxwidget_kill (struct xwidget *xw) | ||
| 474 | { | ||
| 475 | if (xw) | ||
| 476 | { | ||
| 477 | WKUserContentController *scriptor = | ||
| 478 | ((XwWebView *) xw->xwWidget).configuration.userContentController; | ||
| 479 | [scriptor removeAllUserScripts]; | ||
| 480 | [scriptor removeScriptMessageHandlerForName:@"keyDown"]; | ||
| 481 | [scriptor release]; | ||
| 482 | if (xw->xv) | ||
| 483 | xw->xv->model = Qnil; /* Make sure related view stale. */ | ||
| 484 | |||
| 485 | /* This stops playing audio when a xwidget-webkit buffer is | ||
| 486 | killed. I could not find other solution. */ | ||
| 487 | nsxwidget_webkit_goto_uri (xw, "about:blank"); | ||
| 488 | |||
| 489 | [((XwWebView *) xw->xwWidget).urlScriptBlocked release]; | ||
| 490 | [xw->xwWidget removeFromSuperviewWithoutNeedingDisplay]; | ||
| 491 | [xw->xwWidget release]; | ||
| 492 | [xw->xwWindow removeFromSuperviewWithoutNeedingDisplay]; | ||
| 493 | [xw->xwWindow release]; | ||
| 494 | xw->xwWidget = nil; | ||
| 495 | } | ||
| 496 | } | ||
| 497 | |||
| 498 | void | ||
| 499 | nsxwidget_resize (struct xwidget *xw) | ||
| 500 | { | ||
| 501 | if (xw->xwWidget) | ||
| 502 | { | ||
| 503 | [xw->xwWindow setFrameSize:NSMakeSize(xw->width, xw->height)]; | ||
| 504 | [xw->xwWidget setFrameSize:NSMakeSize(xw->width, xw->height)]; | ||
| 505 | } | ||
| 506 | } | ||
| 507 | |||
| 508 | Lisp_Object | ||
| 509 | nsxwidget_get_size (struct xwidget *xw) | ||
| 510 | { | ||
| 511 | return list2i (xw->xwWidget.frame.size.width, | ||
| 512 | xw->xwWidget.frame.size.height); | ||
| 513 | } | ||
| 514 | |||
| 515 | /* Xwidget view, macOS Cocoa part. */ | ||
| 516 | |||
| 517 | @implementation XvWindow : NSView | ||
| 518 | - (BOOL)isFlipped { return YES; } | ||
| 519 | @end | ||
| 520 | |||
| 521 | void | ||
| 522 | nsxwidget_init_view (struct xwidget_view *xv, | ||
| 523 | struct xwidget *xw, | ||
| 524 | struct glyph_string *s, | ||
| 525 | int x, int y) | ||
| 526 | { | ||
| 527 | /* 'x_draw_xwidget_glyph_string' will calculate correct position and | ||
| 528 | size of clip to draw in emacs buffer window. Thus, just begin at | ||
| 529 | origin with no crop. */ | ||
| 530 | xv->x = x; | ||
| 531 | xv->y = y; | ||
| 532 | xv->clip_left = 0; | ||
| 533 | xv->clip_right = xw->width; | ||
| 534 | xv->clip_top = 0; | ||
| 535 | xv->clip_bottom = xw->height; | ||
| 536 | |||
| 537 | xv->xvWindow = [[XvWindow alloc] | ||
| 538 | initWithFrame:NSMakeRect (x, y, xw->width, xw->height)]; | ||
| 539 | xv->xvWindow.xw = xw; | ||
| 540 | xv->xvWindow.xv = xv; | ||
| 541 | |||
| 542 | xw->xv = xv; /* For 1 to 1 relationship of webkit2. */ | ||
| 543 | [xv->xvWindow addSubview:xw->xwWindow]; | ||
| 544 | |||
| 545 | xv->emacswindow = FRAME_NS_VIEW (s->f); | ||
| 546 | [xv->emacswindow addSubview:xv->xvWindow]; | ||
| 547 | } | ||
| 548 | |||
| 549 | void | ||
| 550 | nsxwidget_delete_view (struct xwidget_view *xv) | ||
| 551 | { | ||
| 552 | if (!EQ (xv->model, Qnil)) | ||
| 553 | { | ||
| 554 | struct xwidget *xw = XXWIDGET (xv->model); | ||
| 555 | [xw->xwWindow removeFromSuperviewWithoutNeedingDisplay]; | ||
| 556 | xw->xv = NULL; /* Now model has no view. */ | ||
| 557 | } | ||
| 558 | [xv->xvWindow removeFromSuperviewWithoutNeedingDisplay]; | ||
| 559 | [xv->xvWindow release]; | ||
| 560 | } | ||
| 561 | |||
| 562 | void | ||
| 563 | nsxwidget_show_view (struct xwidget_view *xv) | ||
| 564 | { | ||
| 565 | xv->hidden = NO; | ||
| 566 | [xv->xvWindow setFrameOrigin:NSMakePoint(xv->x + xv->clip_left, | ||
| 567 | xv->y + xv->clip_top)]; | ||
| 568 | } | ||
| 569 | |||
| 570 | void | ||
| 571 | nsxwidget_hide_view (struct xwidget_view *xv) | ||
| 572 | { | ||
| 573 | xv->hidden = YES; | ||
| 574 | [xv->xvWindow setFrameOrigin:NSMakePoint(10000, 10000)]; | ||
| 575 | } | ||
| 576 | |||
| 577 | void | ||
| 578 | nsxwidget_resize_view (struct xwidget_view *xv, int width, int height) | ||
| 579 | { | ||
| 580 | [xv->xvWindow setFrameSize:NSMakeSize(width, height)]; | ||
| 581 | } | ||
| 582 | |||
| 583 | void | ||
| 584 | nsxwidget_move_view (struct xwidget_view *xv, int x, int y) | ||
| 585 | { | ||
| 586 | [xv->xvWindow setFrameOrigin:NSMakePoint (x, y)]; | ||
| 587 | } | ||
| 588 | |||
| 589 | /* Move model window in container (view window). */ | ||
| 590 | void | ||
| 591 | nsxwidget_move_widget_in_view (struct xwidget_view *xv, int x, int y) | ||
| 592 | { | ||
| 593 | struct xwidget *xww = xv->xvWindow.xw; | ||
| 594 | [xww->xwWindow setFrameOrigin:NSMakePoint (x, y)]; | ||
| 595 | } | ||
| 596 | |||
| 597 | void | ||
| 598 | nsxwidget_set_needsdisplay (struct xwidget_view *xv) | ||
| 599 | { | ||
| 600 | xv->xvWindow.needsDisplay = YES; | ||
| 601 | } | ||
diff --git a/src/pdumper.c b/src/pdumper.c index de9c06c9d2c..c55b6f7bb43 100644 --- a/src/pdumper.c +++ b/src/pdumper.c | |||
| @@ -71,17 +71,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | |||
| 71 | #ifdef HAVE_PDUMPER | 71 | #ifdef HAVE_PDUMPER |
| 72 | 72 | ||
| 73 | #if GNUC_PREREQ (4, 7, 0) | 73 | #if GNUC_PREREQ (4, 7, 0) |
| 74 | # pragma GCC diagnostic error "-Wconversion" | ||
| 75 | # pragma GCC diagnostic ignored "-Wsign-conversion" | ||
| 76 | # pragma GCC diagnostic error "-Wshadow" | 74 | # pragma GCC diagnostic error "-Wshadow" |
| 77 | # define ALLOW_IMPLICIT_CONVERSION \ | ||
| 78 | _Pragma ("GCC diagnostic push") \ | ||
| 79 | _Pragma ("GCC diagnostic ignored \"-Wconversion\"") | ||
| 80 | # define DISALLOW_IMPLICIT_CONVERSION \ | ||
| 81 | _Pragma ("GCC diagnostic pop") | ||
| 82 | #else | ||
| 83 | # define ALLOW_IMPLICIT_CONVERSION ((void) 0) | ||
| 84 | # define DISALLOW_IMPLICIT_CONVERSION ((void) 0) | ||
| 85 | #endif | 75 | #endif |
| 86 | 76 | ||
| 87 | #define VM_POSIX 1 | 77 | #define VM_POSIX 1 |
| @@ -105,17 +95,6 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | |||
| 105 | # define VM_SUPPORTED 0 | 95 | # define VM_SUPPORTED 0 |
| 106 | #endif | 96 | #endif |
| 107 | 97 | ||
| 108 | /* PDUMPER_CHECK_REHASHING being true causes the portable dumper to | ||
| 109 | check, for each hash table it dumps, that the hash table means the | ||
| 110 | same thing after rehashing. */ | ||
| 111 | #ifndef PDUMPER_CHECK_REHASHING | ||
| 112 | # if ENABLE_CHECKING | ||
| 113 | # define PDUMPER_CHECK_REHASHING 1 | ||
| 114 | # else | ||
| 115 | # define PDUMPER_CHECK_REHASHING 0 | ||
| 116 | # endif | ||
| 117 | #endif | ||
| 118 | |||
| 119 | /* Require an architecture in which pointers, ptrdiff_t and intptr_t | 98 | /* Require an architecture in which pointers, ptrdiff_t and intptr_t |
| 120 | are the same size and have the same layout, and where bytes have | 99 | are the same size and have the same layout, and where bytes have |
| 121 | eight bits --- that is, a general-purpose computer made after 1990. | 100 | eight bits --- that is, a general-purpose computer made after 1990. |
| @@ -152,8 +131,11 @@ static int nr_remembered_data = 0; | |||
| 152 | typedef int_least32_t dump_off; | 131 | typedef int_least32_t dump_off; |
| 153 | #define DUMP_OFF_MIN INT_LEAST32_MIN | 132 | #define DUMP_OFF_MIN INT_LEAST32_MIN |
| 154 | #define DUMP_OFF_MAX INT_LEAST32_MAX | 133 | #define DUMP_OFF_MAX INT_LEAST32_MAX |
| 134 | #define PRIdDUMP_OFF PRIdLEAST32 | ||
| 135 | |||
| 136 | enum { EMACS_INT_XDIGITS = (EMACS_INT_WIDTH + 3) / 4 }; | ||
| 155 | 137 | ||
| 156 | static void ATTRIBUTE_FORMAT ((printf, 1, 2)) | 138 | static void ATTRIBUTE_FORMAT_PRINTF (1, 2) |
| 157 | dump_trace (const char *fmt, ...) | 139 | dump_trace (const char *fmt, ...) |
| 158 | { | 140 | { |
| 159 | if (0) | 141 | if (0) |
| @@ -326,9 +308,7 @@ static void | |||
| 326 | dump_reloc_set_offset (struct dump_reloc *reloc, dump_off offset) | 308 | dump_reloc_set_offset (struct dump_reloc *reloc, dump_off offset) |
| 327 | { | 309 | { |
| 328 | eassert (offset >= 0); | 310 | eassert (offset >= 0); |
| 329 | ALLOW_IMPLICIT_CONVERSION; | ||
| 330 | reloc->raw_offset = offset >> DUMP_RELOC_ALIGNMENT_BITS; | 311 | reloc->raw_offset = offset >> DUMP_RELOC_ALIGNMENT_BITS; |
| 331 | DISALLOW_IMPLICIT_CONVERSION; | ||
| 332 | if (dump_reloc_get_offset (*reloc) != offset) | 312 | if (dump_reloc_get_offset (*reloc) != offset) |
| 333 | error ("dump relocation out of range"); | 313 | error ("dump relocation out of range"); |
| 334 | } | 314 | } |
| @@ -417,6 +397,9 @@ struct dump_header | |||
| 417 | The start of the cold region is always aligned on a page | 397 | The start of the cold region is always aligned on a page |
| 418 | boundary. */ | 398 | boundary. */ |
| 419 | dump_off cold_start; | 399 | dump_off cold_start; |
| 400 | |||
| 401 | /* Offset of a vector of the dumped hash tables. */ | ||
| 402 | dump_off hash_list; | ||
| 420 | }; | 403 | }; |
| 421 | 404 | ||
| 422 | /* Double-ended singly linked list. */ | 405 | /* Double-ended singly linked list. */ |
| @@ -575,8 +558,11 @@ struct dump_context | |||
| 575 | heap objects. */ | 558 | heap objects. */ |
| 576 | Lisp_Object bignum_data; | 559 | Lisp_Object bignum_data; |
| 577 | 560 | ||
| 578 | unsigned number_hot_relocations; | 561 | /* List of hash tables that have been dumped. */ |
| 579 | unsigned number_discardable_relocations; | 562 | Lisp_Object hash_tables; |
| 563 | |||
| 564 | dump_off number_hot_relocations; | ||
| 565 | dump_off number_discardable_relocations; | ||
| 580 | }; | 566 | }; |
| 581 | 567 | ||
| 582 | /* These special values for use as offsets in dump_remember_object and | 568 | /* These special values for use as offsets in dump_remember_object and |
| @@ -763,10 +749,7 @@ dump_off_from_lisp (Lisp_Object value) | |||
| 763 | { | 749 | { |
| 764 | intmax_t n = intmax_t_from_lisp (value); | 750 | intmax_t n = intmax_t_from_lisp (value); |
| 765 | eassert (DUMP_OFF_MIN <= n && n <= DUMP_OFF_MAX); | 751 | eassert (DUMP_OFF_MIN <= n && n <= DUMP_OFF_MAX); |
| 766 | ALLOW_IMPLICIT_CONVERSION; | 752 | return n; |
| 767 | dump_off converted = n; | ||
| 768 | DISALLOW_IMPLICIT_CONVERSION; | ||
| 769 | return converted; | ||
| 770 | } | 753 | } |
| 771 | 754 | ||
| 772 | static Lisp_Object | 755 | static Lisp_Object |
| @@ -983,11 +966,9 @@ dump_queue_init (struct dump_queue *dump_queue) | |||
| 983 | static bool | 966 | static bool |
| 984 | dump_queue_empty_p (struct dump_queue *dump_queue) | 967 | dump_queue_empty_p (struct dump_queue *dump_queue) |
| 985 | { | 968 | { |
| 986 | bool is_empty = | 969 | ptrdiff_t count = XHASH_TABLE (dump_queue->sequence_numbers)->count; |
| 987 | EQ (Fhash_table_count (dump_queue->sequence_numbers), | 970 | bool is_empty = count == 0; |
| 988 | make_fixnum (0)); | 971 | eassert (count == XFIXNAT (Fhash_table_count (dump_queue->link_weights))); |
| 989 | eassert (EQ (Fhash_table_count (dump_queue->sequence_numbers), | ||
| 990 | Fhash_table_count (dump_queue->link_weights))); | ||
| 991 | if (!is_empty) | 972 | if (!is_empty) |
| 992 | { | 973 | { |
| 993 | eassert (!dump_tailq_empty_p (&dump_queue->zero_weight_objects) | 974 | eassert (!dump_tailq_empty_p (&dump_queue->zero_weight_objects) |
| @@ -1029,9 +1010,9 @@ dump_queue_enqueue (struct dump_queue *dump_queue, | |||
| 1029 | if (NILP (weights)) | 1010 | if (NILP (weights)) |
| 1030 | { | 1011 | { |
| 1031 | /* Object is new. */ | 1012 | /* Object is new. */ |
| 1032 | dump_trace ("new object %016x weight=%u\n", | 1013 | EMACS_UINT uobj = XLI (object); |
| 1033 | (unsigned) XLI (object), | 1014 | dump_trace ("new object %0*"pI"x weight=%d\n", EMACS_INT_XDIGITS, uobj, |
| 1034 | (unsigned) weight.value); | 1015 | weight.value); |
| 1035 | 1016 | ||
| 1036 | if (weight.value == WEIGHT_NONE.value) | 1017 | if (weight.value == WEIGHT_NONE.value) |
| 1037 | { | 1018 | { |
| @@ -1246,17 +1227,15 @@ dump_queue_dequeue (struct dump_queue *dump_queue, dump_off basis) | |||
| 1246 | + dump_tailq_length (&dump_queue->one_weight_normal_objects) | 1227 | + dump_tailq_length (&dump_queue->one_weight_normal_objects) |
| 1247 | + dump_tailq_length (&dump_queue->one_weight_strong_objects))); | 1228 | + dump_tailq_length (&dump_queue->one_weight_strong_objects))); |
| 1248 | 1229 | ||
| 1249 | bool dump_object_counts = true; | 1230 | dump_trace |
| 1250 | if (dump_object_counts) | 1231 | (("dump_queue_dequeue basis=%"PRIdDUMP_OFF" fancy=%"PRIdPTR |
| 1251 | dump_trace | 1232 | " zero=%"PRIdPTR" normal=%"PRIdPTR" strong=%"PRIdPTR" hash=%td\n"), |
| 1252 | ("dump_queue_dequeue basis=%d fancy=%u zero=%u " | 1233 | basis, |
| 1253 | "normal=%u strong=%u hash=%u\n", | 1234 | dump_tailq_length (&dump_queue->fancy_weight_objects), |
| 1254 | basis, | 1235 | dump_tailq_length (&dump_queue->zero_weight_objects), |
| 1255 | (unsigned) dump_tailq_length (&dump_queue->fancy_weight_objects), | 1236 | dump_tailq_length (&dump_queue->one_weight_normal_objects), |
| 1256 | (unsigned) dump_tailq_length (&dump_queue->zero_weight_objects), | 1237 | dump_tailq_length (&dump_queue->one_weight_strong_objects), |
| 1257 | (unsigned) dump_tailq_length (&dump_queue->one_weight_normal_objects), | 1238 | XHASH_TABLE (dump_queue->link_weights)->count); |
| 1258 | (unsigned) dump_tailq_length (&dump_queue->one_weight_strong_objects), | ||
| 1259 | (unsigned) XFIXNUM (Fhash_table_count (dump_queue->link_weights))); | ||
| 1260 | 1239 | ||
| 1261 | static const int nr_candidates = 3; | 1240 | static const int nr_candidates = 3; |
| 1262 | struct candidate | 1241 | struct candidate |
| @@ -1329,10 +1308,10 @@ dump_queue_dequeue (struct dump_queue *dump_queue, dump_off basis) | |||
| 1329 | else | 1308 | else |
| 1330 | emacs_abort (); | 1309 | emacs_abort (); |
| 1331 | 1310 | ||
| 1332 | dump_trace (" result score=%f src=%s object=%016x\n", | 1311 | EMACS_UINT uresult = XLI (result); |
| 1312 | dump_trace (" result score=%f src=%s object=%0*"pI"x\n", | ||
| 1333 | best < 0 ? -1.0 : (double) candidates[best].score, | 1313 | best < 0 ? -1.0 : (double) candidates[best].score, |
| 1334 | src, | 1314 | src, EMACS_INT_XDIGITS, uresult); |
| 1335 | (unsigned) XLI (result)); | ||
| 1336 | 1315 | ||
| 1337 | { | 1316 | { |
| 1338 | Lisp_Object weights = Fgethash (result, dump_queue->link_weights, Qnil); | 1317 | Lisp_Object weights = Fgethash (result, dump_queue->link_weights, Qnil); |
| @@ -2017,11 +1996,7 @@ static dump_off | |||
| 2017 | finish_dump_pvec (struct dump_context *ctx, | 1996 | finish_dump_pvec (struct dump_context *ctx, |
| 2018 | union vectorlike_header *out_hdr) | 1997 | union vectorlike_header *out_hdr) |
| 2019 | { | 1998 | { |
| 2020 | ALLOW_IMPLICIT_CONVERSION; | 1999 | return dump_object_finish (ctx, out_hdr, vectorlike_nbytes (out_hdr)); |
| 2021 | dump_off result = dump_object_finish (ctx, out_hdr, | ||
| 2022 | vectorlike_nbytes (out_hdr)); | ||
| 2023 | DISALLOW_IMPLICIT_CONVERSION; | ||
| 2024 | return result; | ||
| 2025 | } | 2000 | } |
| 2026 | 2001 | ||
| 2027 | static void | 2002 | static void |
| @@ -2633,78 +2608,65 @@ dump_vectorlike_generic (struct dump_context *ctx, | |||
| 2633 | return offset; | 2608 | return offset; |
| 2634 | } | 2609 | } |
| 2635 | 2610 | ||
| 2636 | /* Determine whether the hash table's hash order is stable | 2611 | /* Return a vector of KEY, VALUE pairs in the given hash table H. The |
| 2637 | across dump and load. If it is, we don't have to trigger | 2612 | first H->count pairs are valid, and the rest are unbound. */ |
| 2638 | a rehash on access. */ | 2613 | static Lisp_Object |
| 2639 | static bool | 2614 | hash_table_contents (struct Lisp_Hash_Table *h) |
| 2640 | dump_hash_table_stable_p (const struct Lisp_Hash_Table *hash) | ||
| 2641 | { | 2615 | { |
| 2642 | if (hash->test.hashfn == hashfn_user_defined) | 2616 | if (h->test.hashfn == hashfn_user_defined) |
| 2643 | error ("cannot dump hash tables with user-defined tests"); /* Bug#36769 */ | 2617 | error ("cannot dump hash tables with user-defined tests"); /* Bug#36769 */ |
| 2644 | bool is_eql = hash->test.hashfn == hashfn_eql; | 2618 | |
| 2645 | bool is_equal = hash->test.hashfn == hashfn_equal; | 2619 | ptrdiff_t size = HASH_TABLE_SIZE (h); |
| 2646 | ptrdiff_t size = HASH_TABLE_SIZE (hash); | 2620 | Lisp_Object key_and_value = make_uninit_vector (2 * size); |
| 2647 | for (ptrdiff_t i = 0; i < size; ++i) | 2621 | ptrdiff_t n = 0; |
| 2622 | |||
| 2623 | /* Make sure key_and_value ends up in the same order; charset.c | ||
| 2624 | relies on it by expecting hash table indices to stay constant | ||
| 2625 | across the dump. */ | ||
| 2626 | for (ptrdiff_t i = 0; i < size; i++) | ||
| 2627 | if (!NILP (HASH_HASH (h, i))) | ||
| 2628 | { | ||
| 2629 | ASET (key_and_value, n++, HASH_KEY (h, i)); | ||
| 2630 | ASET (key_and_value, n++, HASH_VALUE (h, i)); | ||
| 2631 | } | ||
| 2632 | |||
| 2633 | while (n < 2 * size) | ||
| 2648 | { | 2634 | { |
| 2649 | Lisp_Object key = HASH_KEY (hash, i); | 2635 | ASET (key_and_value, n++, Qunbound); |
| 2650 | if (!EQ (key, Qunbound)) | 2636 | ASET (key_and_value, n++, Qnil); |
| 2651 | { | ||
| 2652 | bool key_stable = (dump_builtin_symbol_p (key) | ||
| 2653 | || FIXNUMP (key) | ||
| 2654 | || (is_equal | ||
| 2655 | && (STRINGP (key) || BOOL_VECTOR_P (key))) | ||
| 2656 | || ((is_equal || is_eql) | ||
| 2657 | && (FLOATP (key) || BIGNUMP (key)))); | ||
| 2658 | if (!key_stable) | ||
| 2659 | return false; | ||
| 2660 | } | ||
| 2661 | } | 2637 | } |
| 2662 | 2638 | ||
| 2663 | return true; | 2639 | return key_and_value; |
| 2664 | } | 2640 | } |
| 2665 | 2641 | ||
| 2666 | /* Return a list of (KEY . VALUE) pairs in the given hash table. */ | 2642 | static dump_off |
| 2667 | static Lisp_Object | 2643 | dump_hash_table_list (struct dump_context *ctx) |
| 2668 | hash_table_contents (Lisp_Object table) | ||
| 2669 | { | 2644 | { |
| 2670 | Lisp_Object contents = Qnil; | 2645 | if (!NILP (ctx->hash_tables)) |
| 2671 | struct Lisp_Hash_Table *h = XHASH_TABLE (table); | 2646 | return dump_object (ctx, CALLN (Fapply, Qvector, ctx->hash_tables)); |
| 2672 | for (ptrdiff_t i = 0; i < HASH_TABLE_SIZE (h); ++i) | 2647 | else |
| 2673 | { | 2648 | return 0; |
| 2674 | Lisp_Object key = HASH_KEY (h, i); | ||
| 2675 | if (!EQ (key, Qunbound)) | ||
| 2676 | dump_push (&contents, Fcons (key, HASH_VALUE (h, i))); | ||
| 2677 | } | ||
| 2678 | return Fnreverse (contents); | ||
| 2679 | } | 2649 | } |
| 2680 | 2650 | ||
| 2681 | /* Copy the given hash table, rehash it, and make sure that we can | ||
| 2682 | look up all the values in the original. */ | ||
| 2683 | static void | 2651 | static void |
| 2684 | check_hash_table_rehash (Lisp_Object table_orig) | 2652 | hash_table_freeze (struct Lisp_Hash_Table *h) |
| 2685 | { | 2653 | { |
| 2686 | ptrdiff_t count = XHASH_TABLE (table_orig)->count; | 2654 | ptrdiff_t npairs = ASIZE (h->key_and_value) / 2; |
| 2687 | hash_rehash_if_needed (XHASH_TABLE (table_orig)); | 2655 | h->key_and_value = hash_table_contents (h); |
| 2688 | Lisp_Object table_rehashed = Fcopy_hash_table (table_orig); | 2656 | h->next = h->hash = make_fixnum (npairs); |
| 2689 | eassert (!hash_rehash_needed_p (XHASH_TABLE (table_rehashed))); | 2657 | h->index = make_fixnum (ASIZE (h->index)); |
| 2690 | XHASH_TABLE (table_rehashed)->hash = Qnil; | 2658 | h->next_free = (npairs == h->count ? -1 : h->count); |
| 2691 | eassert (count == 0 || hash_rehash_needed_p (XHASH_TABLE (table_rehashed))); | 2659 | } |
| 2692 | hash_rehash_if_needed (XHASH_TABLE (table_rehashed)); | ||
| 2693 | eassert (!hash_rehash_needed_p (XHASH_TABLE (table_rehashed))); | ||
| 2694 | Lisp_Object expected_contents = hash_table_contents (table_orig); | ||
| 2695 | while (!NILP (expected_contents)) | ||
| 2696 | { | ||
| 2697 | Lisp_Object key_value_pair = dump_pop (&expected_contents); | ||
| 2698 | Lisp_Object key = XCAR (key_value_pair); | ||
| 2699 | Lisp_Object expected_value = XCDR (key_value_pair); | ||
| 2700 | Lisp_Object arbitrary = Qdump_emacs_portable__sort_predicate_copied; | ||
| 2701 | Lisp_Object found_value = Fgethash (key, table_rehashed, arbitrary); | ||
| 2702 | eassert (EQ (expected_value, found_value)); | ||
| 2703 | Fremhash (key, table_rehashed); | ||
| 2704 | } | ||
| 2705 | 2660 | ||
| 2706 | eassert (EQ (Fhash_table_count (table_rehashed), | 2661 | static void |
| 2707 | make_fixnum (0))); | 2662 | hash_table_thaw (Lisp_Object hash) |
| 2663 | { | ||
| 2664 | struct Lisp_Hash_Table *h = XHASH_TABLE (hash); | ||
| 2665 | h->hash = make_nil_vector (XFIXNUM (h->hash)); | ||
| 2666 | h->next = Fmake_vector (h->next, make_fixnum (-1)); | ||
| 2667 | h->index = Fmake_vector (h->index, make_fixnum (-1)); | ||
| 2668 | |||
| 2669 | hash_table_rehash (hash); | ||
| 2708 | } | 2670 | } |
| 2709 | 2671 | ||
| 2710 | static dump_off | 2672 | static dump_off |
| @@ -2712,55 +2674,15 @@ dump_hash_table (struct dump_context *ctx, | |||
| 2712 | Lisp_Object object, | 2674 | Lisp_Object object, |
| 2713 | dump_off offset) | 2675 | dump_off offset) |
| 2714 | { | 2676 | { |
| 2715 | #if CHECK_STRUCTS && !defined HASH_Lisp_Hash_Table_12AFBF47AF | 2677 | #if CHECK_STRUCTS && !defined HASH_Lisp_Hash_Table_6D63EDB618 |
| 2716 | # error "Lisp_Hash_Table changed. See CHECK_STRUCTS comment in config.h." | 2678 | # error "Lisp_Hash_Table changed. See CHECK_STRUCTS comment in config.h." |
| 2717 | #endif | 2679 | #endif |
| 2718 | const struct Lisp_Hash_Table *hash_in = XHASH_TABLE (object); | 2680 | const struct Lisp_Hash_Table *hash_in = XHASH_TABLE (object); |
| 2719 | bool is_stable = dump_hash_table_stable_p (hash_in); | ||
| 2720 | /* If the hash table is likely to be modified in memory (either | ||
| 2721 | because we need to rehash, and thus toggle hash->count, or | ||
| 2722 | because we need to assemble a list of weak tables) punt the hash | ||
| 2723 | table to the end of the dump, where we can lump all such hash | ||
| 2724 | tables together. */ | ||
| 2725 | if (!(is_stable || !NILP (hash_in->weak)) | ||
| 2726 | && ctx->flags.defer_hash_tables) | ||
| 2727 | { | ||
| 2728 | if (offset != DUMP_OBJECT_ON_HASH_TABLE_QUEUE) | ||
| 2729 | { | ||
| 2730 | eassert (offset == DUMP_OBJECT_ON_NORMAL_QUEUE | ||
| 2731 | || offset == DUMP_OBJECT_NOT_SEEN); | ||
| 2732 | /* We still want to dump the actual keys and values now. */ | ||
| 2733 | dump_enqueue_object (ctx, hash_in->key_and_value, WEIGHT_NONE); | ||
| 2734 | /* We'll get to the rest later. */ | ||
| 2735 | offset = DUMP_OBJECT_ON_HASH_TABLE_QUEUE; | ||
| 2736 | dump_remember_object (ctx, object, offset); | ||
| 2737 | dump_push (&ctx->deferred_hash_tables, object); | ||
| 2738 | } | ||
| 2739 | return offset; | ||
| 2740 | } | ||
| 2741 | |||
| 2742 | if (PDUMPER_CHECK_REHASHING) | ||
| 2743 | check_hash_table_rehash (make_lisp_ptr ((void *) hash_in, Lisp_Vectorlike)); | ||
| 2744 | |||
| 2745 | struct Lisp_Hash_Table hash_munged = *hash_in; | 2681 | struct Lisp_Hash_Table hash_munged = *hash_in; |
| 2746 | struct Lisp_Hash_Table *hash = &hash_munged; | 2682 | struct Lisp_Hash_Table *hash = &hash_munged; |
| 2747 | 2683 | ||
| 2748 | /* Remember to rehash this hash table on first access. After a | 2684 | hash_table_freeze (hash); |
| 2749 | dump reload, the hash table values will have changed, so we'll | 2685 | dump_push (&ctx->hash_tables, object); |
| 2750 | need to rebuild the index. | ||
| 2751 | |||
| 2752 | TODO: for EQ and EQL hash tables, it should be possible to rehash | ||
| 2753 | here using the preferred load address of the dump, eliminating | ||
| 2754 | the need to rehash-on-access if we can load the dump where we | ||
| 2755 | want. */ | ||
| 2756 | if (hash->count > 0 && !is_stable) | ||
| 2757 | /* Hash codes will have to be recomputed anyway, so let's not dump them. | ||
| 2758 | Also set `hash` to nil for hash_rehash_needed_p. | ||
| 2759 | We could also refrain from dumping the `next' and `index' vectors, | ||
| 2760 | except that `next' is currently used for HASH_TABLE_SIZE and | ||
| 2761 | we'd have to rebuild the next_free list as well as adjust | ||
| 2762 | sweep_weak_hash_table for the case where there's no `index'. */ | ||
| 2763 | hash->hash = Qnil; | ||
| 2764 | 2686 | ||
| 2765 | START_DUMP_PVEC (ctx, &hash->header, struct Lisp_Hash_Table, out); | 2687 | START_DUMP_PVEC (ctx, &hash->header, struct Lisp_Hash_Table, out); |
| 2766 | dump_pseudovector_lisp_fields (ctx, &out->header, &hash->header); | 2688 | dump_pseudovector_lisp_fields (ctx, &out->header, &hash->header); |
| @@ -3429,9 +3351,7 @@ static void | |||
| 3429 | dump_cold_charset (struct dump_context *ctx, Lisp_Object data) | 3351 | dump_cold_charset (struct dump_context *ctx, Lisp_Object data) |
| 3430 | { | 3352 | { |
| 3431 | /* Dump charset lookup tables. */ | 3353 | /* Dump charset lookup tables. */ |
| 3432 | ALLOW_IMPLICIT_CONVERSION; | ||
| 3433 | int cs_i = XFIXNUM (XCAR (data)); | 3354 | int cs_i = XFIXNUM (XCAR (data)); |
| 3434 | DISALLOW_IMPLICIT_CONVERSION; | ||
| 3435 | dump_off cs_dump_offset = dump_off_from_lisp (XCDR (data)); | 3355 | dump_off cs_dump_offset = dump_off_from_lisp (XCDR (data)); |
| 3436 | dump_remember_fixup_ptr_raw | 3356 | dump_remember_fixup_ptr_raw |
| 3437 | (ctx, | 3357 | (ctx, |
| @@ -3767,9 +3687,7 @@ static struct emacs_reloc | |||
| 3767 | decode_emacs_reloc (struct dump_context *ctx, Lisp_Object lreloc) | 3687 | decode_emacs_reloc (struct dump_context *ctx, Lisp_Object lreloc) |
| 3768 | { | 3688 | { |
| 3769 | struct emacs_reloc reloc = {0}; | 3689 | struct emacs_reloc reloc = {0}; |
| 3770 | ALLOW_IMPLICIT_CONVERSION; | ||
| 3771 | int type = XFIXNUM (dump_pop (&lreloc)); | 3690 | int type = XFIXNUM (dump_pop (&lreloc)); |
| 3772 | DISALLOW_IMPLICIT_CONVERSION; | ||
| 3773 | reloc.emacs_offset = dump_off_from_lisp (dump_pop (&lreloc)); | 3691 | reloc.emacs_offset = dump_off_from_lisp (dump_pop (&lreloc)); |
| 3774 | dump_check_emacs_off (reloc.emacs_offset); | 3692 | dump_check_emacs_off (reloc.emacs_offset); |
| 3775 | switch (type) | 3693 | switch (type) |
| @@ -3780,9 +3698,7 @@ decode_emacs_reloc (struct dump_context *ctx, Lisp_Object lreloc) | |||
| 3780 | reloc.u.dump_offset = dump_off_from_lisp (dump_pop (&lreloc)); | 3698 | reloc.u.dump_offset = dump_off_from_lisp (dump_pop (&lreloc)); |
| 3781 | dump_check_dump_off (ctx, reloc.u.dump_offset); | 3699 | dump_check_dump_off (ctx, reloc.u.dump_offset); |
| 3782 | dump_off length = dump_off_from_lisp (dump_pop (&lreloc)); | 3700 | dump_off length = dump_off_from_lisp (dump_pop (&lreloc)); |
| 3783 | ALLOW_IMPLICIT_CONVERSION; | ||
| 3784 | reloc.length = length; | 3701 | reloc.length = length; |
| 3785 | DISALLOW_IMPLICIT_CONVERSION; | ||
| 3786 | if (reloc.length != length) | 3702 | if (reloc.length != length) |
| 3787 | error ("relocation copy length too large"); | 3703 | error ("relocation copy length too large"); |
| 3788 | } | 3704 | } |
| @@ -3793,9 +3709,7 @@ decode_emacs_reloc (struct dump_context *ctx, Lisp_Object lreloc) | |||
| 3793 | intmax_t value = intmax_t_from_lisp (dump_pop (&lreloc)); | 3709 | intmax_t value = intmax_t_from_lisp (dump_pop (&lreloc)); |
| 3794 | dump_off size = dump_off_from_lisp (dump_pop (&lreloc)); | 3710 | dump_off size = dump_off_from_lisp (dump_pop (&lreloc)); |
| 3795 | reloc.u.immediate = value; | 3711 | reloc.u.immediate = value; |
| 3796 | ALLOW_IMPLICIT_CONVERSION; | ||
| 3797 | reloc.length = size; | 3712 | reloc.length = size; |
| 3798 | DISALLOW_IMPLICIT_CONVERSION; | ||
| 3799 | eassert (reloc.length == size); | 3713 | eassert (reloc.length == size); |
| 3800 | } | 3714 | } |
| 3801 | break; | 3715 | break; |
| @@ -3820,9 +3734,7 @@ decode_emacs_reloc (struct dump_context *ctx, Lisp_Object lreloc) | |||
| 3820 | RELOC_EMACS_IMMEDIATE relocation instead. */ | 3734 | RELOC_EMACS_IMMEDIATE relocation instead. */ |
| 3821 | eassert (!dump_object_self_representing_p (target_value)); | 3735 | eassert (!dump_object_self_representing_p (target_value)); |
| 3822 | int tag_type = XTYPE (target_value); | 3736 | int tag_type = XTYPE (target_value); |
| 3823 | ALLOW_IMPLICIT_CONVERSION; | ||
| 3824 | reloc.length = tag_type; | 3737 | reloc.length = tag_type; |
| 3825 | DISALLOW_IMPLICIT_CONVERSION; | ||
| 3826 | eassert (reloc.length == tag_type); | 3738 | eassert (reloc.length == tag_type); |
| 3827 | 3739 | ||
| 3828 | if (type == RELOC_EMACS_EMACS_LV) | 3740 | if (type == RELOC_EMACS_EMACS_LV) |
| @@ -3897,9 +3809,7 @@ dump_merge_emacs_relocs (Lisp_Object lreloc_a, Lisp_Object lreloc_b) | |||
| 3897 | return Qnil; | 3809 | return Qnil; |
| 3898 | 3810 | ||
| 3899 | dump_off new_length = reloc_a.length + reloc_b.length; | 3811 | dump_off new_length = reloc_a.length + reloc_b.length; |
| 3900 | ALLOW_IMPLICIT_CONVERSION; | ||
| 3901 | reloc_a.length = new_length; | 3812 | reloc_a.length = new_length; |
| 3902 | DISALLOW_IMPLICIT_CONVERSION; | ||
| 3903 | if (reloc_a.length != new_length) | 3813 | if (reloc_a.length != new_length) |
| 3904 | return Qnil; /* Overflow */ | 3814 | return Qnil; /* Overflow */ |
| 3905 | 3815 | ||
| @@ -4254,6 +4164,19 @@ types. */) | |||
| 4254 | || !NILP (ctx->deferred_hash_tables) | 4164 | || !NILP (ctx->deferred_hash_tables) |
| 4255 | || !NILP (ctx->deferred_symbols)); | 4165 | || !NILP (ctx->deferred_symbols)); |
| 4256 | 4166 | ||
| 4167 | ctx->header.hash_list = ctx->offset; | ||
| 4168 | dump_hash_table_list (ctx); | ||
| 4169 | |||
| 4170 | do | ||
| 4171 | { | ||
| 4172 | dump_drain_deferred_hash_tables (ctx); | ||
| 4173 | dump_drain_deferred_symbols (ctx); | ||
| 4174 | dump_drain_normal_queue (ctx); | ||
| 4175 | } | ||
| 4176 | while (!dump_queue_empty_p (&ctx->dump_queue) | ||
| 4177 | || !NILP (ctx->deferred_hash_tables) | ||
| 4178 | || !NILP (ctx->deferred_symbols)); | ||
| 4179 | |||
| 4257 | dump_sort_copied_objects (ctx); | 4180 | dump_sort_copied_objects (ctx); |
| 4258 | 4181 | ||
| 4259 | /* While we copy built-in symbols into the Emacs image, these | 4182 | /* While we copy built-in symbols into the Emacs image, these |
| @@ -4314,9 +4237,9 @@ types. */) | |||
| 4314 | for (int i = 0; i < RELOC_NUM_PHASES; ++i) | 4237 | for (int i = 0; i < RELOC_NUM_PHASES; ++i) |
| 4315 | drain_reloc_list (ctx, dump_emit_dump_reloc, emacs_reloc_merger, | 4238 | drain_reloc_list (ctx, dump_emit_dump_reloc, emacs_reloc_merger, |
| 4316 | &ctx->dump_relocs[i], &ctx->header.dump_relocs[i]); | 4239 | &ctx->dump_relocs[i], &ctx->header.dump_relocs[i]); |
| 4317 | unsigned number_hot_relocations = ctx->number_hot_relocations; | 4240 | dump_off number_hot_relocations = ctx->number_hot_relocations; |
| 4318 | ctx->number_hot_relocations = 0; | 4241 | ctx->number_hot_relocations = 0; |
| 4319 | unsigned number_discardable_relocations = ctx->number_discardable_relocations; | 4242 | dump_off number_discardable_relocations = ctx->number_discardable_relocations; |
| 4320 | ctx->number_discardable_relocations = 0; | 4243 | ctx->number_discardable_relocations = 0; |
| 4321 | drain_reloc_list (ctx, dump_emit_dump_reloc, emacs_reloc_merger, | 4244 | drain_reloc_list (ctx, dump_emit_dump_reloc, emacs_reloc_merger, |
| 4322 | &ctx->object_starts, &ctx->header.object_starts); | 4245 | &ctx->object_starts, &ctx->header.object_starts); |
| @@ -4341,14 +4264,17 @@ types. */) | |||
| 4341 | dump_seek (ctx, 0); | 4264 | dump_seek (ctx, 0); |
| 4342 | dump_write (ctx, &ctx->header, sizeof (ctx->header)); | 4265 | dump_write (ctx, &ctx->header, sizeof (ctx->header)); |
| 4343 | 4266 | ||
| 4267 | dump_off | ||
| 4268 | header_bytes = header_end - header_start, | ||
| 4269 | hot_bytes = hot_end - hot_start, | ||
| 4270 | discardable_bytes = discardable_end - ctx->header.discardable_start, | ||
| 4271 | cold_bytes = cold_end - ctx->header.cold_start; | ||
| 4344 | fprintf (stderr, | 4272 | fprintf (stderr, |
| 4345 | ("Dump complete\n" | 4273 | ("Dump complete\n" |
| 4346 | "Byte counts: header=%lu hot=%lu discardable=%lu cold=%lu\n" | 4274 | "Byte counts: header=%"PRIdDUMP_OFF" hot=%"PRIdDUMP_OFF |
| 4347 | "Reloc counts: hot=%u discardable=%u\n"), | 4275 | " discardable=%"PRIdDUMP_OFF" cold=%"PRIdDUMP_OFF"\n" |
| 4348 | (unsigned long) (header_end - header_start), | 4276 | "Reloc counts: hot=%"PRIdDUMP_OFF" discardable=%"PRIdDUMP_OFF"\n"), |
| 4349 | (unsigned long) (hot_end - hot_start), | 4277 | header_bytes, hot_bytes, discardable_bytes, cold_bytes, |
| 4350 | (unsigned long) (discardable_end - ctx->header.discardable_start), | ||
| 4351 | (unsigned long) (cold_end - ctx->header.cold_start), | ||
| 4352 | number_hot_relocations, | 4278 | number_hot_relocations, |
| 4353 | number_discardable_relocations); | 4279 | number_discardable_relocations); |
| 4354 | 4280 | ||
| @@ -5214,14 +5140,13 @@ dump_read_all (int fd, void *buf, size_t bytes_to_read) | |||
| 5214 | { | 5140 | { |
| 5215 | /* We don't want to use emacs_read, since that relies on the lisp | 5141 | /* We don't want to use emacs_read, since that relies on the lisp |
| 5216 | world, and we're not in the lisp world yet. */ | 5142 | world, and we're not in the lisp world yet. */ |
| 5217 | eassert (bytes_to_read <= SSIZE_MAX); | ||
| 5218 | size_t bytes_read = 0; | 5143 | size_t bytes_read = 0; |
| 5219 | while (bytes_read < bytes_to_read) | 5144 | while (bytes_read < bytes_to_read) |
| 5220 | { | 5145 | { |
| 5221 | /* Some platforms accept only int-sized values to read. */ | 5146 | /* Some platforms accept only int-sized values to read. |
| 5222 | unsigned chunk_to_read = INT_MAX; | 5147 | Round this down to a page size (see MAX_RW_COUNT in sysdep.c). */ |
| 5223 | if (bytes_to_read - bytes_read < chunk_to_read) | 5148 | int max_rw_count = INT_MAX >> 18 << 18; |
| 5224 | chunk_to_read = (unsigned) (bytes_to_read - bytes_read); | 5149 | int chunk_to_read = min (bytes_to_read - bytes_read, max_rw_count); |
| 5225 | ssize_t chunk = read (fd, (char *) buf + bytes_read, chunk_to_read); | 5150 | ssize_t chunk = read (fd, (char *) buf + bytes_read, chunk_to_read); |
| 5226 | if (chunk < 0) | 5151 | if (chunk < 0) |
| 5227 | return chunk; | 5152 | return chunk; |
| @@ -5485,6 +5410,9 @@ enum dump_section | |||
| 5485 | NUMBER_DUMP_SECTIONS, | 5410 | NUMBER_DUMP_SECTIONS, |
| 5486 | }; | 5411 | }; |
| 5487 | 5412 | ||
| 5413 | /* Pointer to a stack variable to avoid having to staticpro it. */ | ||
| 5414 | static Lisp_Object *pdumper_hashes = &zero_vector; | ||
| 5415 | |||
| 5488 | /* Load a dump from DUMP_FILENAME. Return an error code. | 5416 | /* Load a dump from DUMP_FILENAME. Return an error code. |
| 5489 | 5417 | ||
| 5490 | N.B. We run very early in initialization, so we can't use lisp, | 5418 | N.B. We run very early in initialization, so we can't use lisp, |
| @@ -5631,6 +5559,15 @@ pdumper_load (const char *dump_filename, char *argv0, char const *original_pwd) | |||
| 5631 | for (int i = 0; i < ARRAYELTS (sections); ++i) | 5559 | for (int i = 0; i < ARRAYELTS (sections); ++i) |
| 5632 | dump_mmap_reset (§ions[i]); | 5560 | dump_mmap_reset (§ions[i]); |
| 5633 | 5561 | ||
| 5562 | Lisp_Object hashes = zero_vector; | ||
| 5563 | if (header->hash_list) | ||
| 5564 | { | ||
| 5565 | struct Lisp_Vector *hash_tables = | ||
| 5566 | (struct Lisp_Vector *) (dump_base + header->hash_list); | ||
| 5567 | hashes = make_lisp_ptr (hash_tables, Lisp_Vectorlike); | ||
| 5568 | } | ||
| 5569 | |||
| 5570 | pdumper_hashes = &hashes; | ||
| 5634 | /* Run the functions Emacs registered for doing post-dump-load | 5571 | /* Run the functions Emacs registered for doing post-dump-load |
| 5635 | initialization. */ | 5572 | initialization. */ |
| 5636 | for (int i = 0; i < nr_dump_hooks; ++i) | 5573 | for (int i = 0; i < nr_dump_hooks; ++i) |
| @@ -5707,6 +5644,19 @@ Value is nil if this session was not started using a dump file.*/) | |||
| 5707 | #endif /* HAVE_PDUMPER */ | 5644 | #endif /* HAVE_PDUMPER */ |
| 5708 | 5645 | ||
| 5709 | 5646 | ||
| 5647 | static void | ||
| 5648 | thaw_hash_tables (void) | ||
| 5649 | { | ||
| 5650 | Lisp_Object hash_tables = *pdumper_hashes; | ||
| 5651 | for (ptrdiff_t i = 0; i < ASIZE (hash_tables); i++) | ||
| 5652 | hash_table_thaw (AREF (hash_tables, i)); | ||
| 5653 | } | ||
| 5654 | |||
| 5655 | void | ||
| 5656 | init_pdumper_once (void) | ||
| 5657 | { | ||
| 5658 | pdumper_do_now_and_after_load (thaw_hash_tables); | ||
| 5659 | } | ||
| 5710 | 5660 | ||
| 5711 | void | 5661 | void |
| 5712 | syms_of_pdumper (void) | 5662 | syms_of_pdumper (void) |
diff --git a/src/pdumper.h b/src/pdumper.h index b92958e12bc..c4baeaf8f94 100644 --- a/src/pdumper.h +++ b/src/pdumper.h | |||
| @@ -257,6 +257,7 @@ pdumper_clear_marks (void) | |||
| 257 | file was loaded. */ | 257 | file was loaded. */ |
| 258 | extern void pdumper_record_wd (const char *); | 258 | extern void pdumper_record_wd (const char *); |
| 259 | 259 | ||
| 260 | void init_pdumper_once (void); | ||
| 260 | void syms_of_pdumper (void); | 261 | void syms_of_pdumper (void); |
| 261 | 262 | ||
| 262 | INLINE_HEADER_END | 263 | INLINE_HEADER_END |
diff --git a/src/timefns.c b/src/timefns.c index 7bcc37d7c1e..94cfddf0da9 100644 --- a/src/timefns.c +++ b/src/timefns.c | |||
| @@ -2048,7 +2048,7 @@ syms_of_timefns (void) | |||
| 2048 | defsubr (&Scurrent_time_zone); | 2048 | defsubr (&Scurrent_time_zone); |
| 2049 | defsubr (&Sset_time_zone_rule); | 2049 | defsubr (&Sset_time_zone_rule); |
| 2050 | 2050 | ||
| 2051 | flt_radix_power = make_vector (flt_radix_power_size, Qnil); | 2051 | flt_radix_power = make_nil_vector (flt_radix_power_size); |
| 2052 | staticpro (&flt_radix_power); | 2052 | staticpro (&flt_radix_power); |
| 2053 | 2053 | ||
| 2054 | #ifdef NEED_ZTRILLION_INIT | 2054 | #ifdef NEED_ZTRILLION_INIT |
diff --git a/src/xfaces.c b/src/xfaces.c index 585cfa1cf4a..2c6e593f631 100644 --- a/src/xfaces.c +++ b/src/xfaces.c | |||
| @@ -2517,6 +2517,7 @@ merge_face_ref (struct window *w, | |||
| 2517 | { | 2517 | { |
| 2518 | bool ok = true; /* Succeed without an error? */ | 2518 | bool ok = true; /* Succeed without an error? */ |
| 2519 | Lisp_Object filtered_face_ref; | 2519 | Lisp_Object filtered_face_ref; |
| 2520 | bool attr_filter_passed = false; | ||
| 2520 | 2521 | ||
| 2521 | filtered_face_ref = face_ref; | 2522 | filtered_face_ref = face_ref; |
| 2522 | do | 2523 | do |
| @@ -2613,6 +2614,7 @@ merge_face_ref (struct window *w, | |||
| 2613 | || UNSPECIFIEDP (scratch_attrs[attr_filter])) | 2614 | || UNSPECIFIEDP (scratch_attrs[attr_filter])) |
| 2614 | return true; | 2615 | return true; |
| 2615 | } | 2616 | } |
| 2617 | attr_filter_passed = true; | ||
| 2616 | } | 2618 | } |
| 2617 | while (CONSP (face_ref) && CONSP (XCDR (face_ref))) | 2619 | while (CONSP (face_ref) && CONSP (XCDR (face_ref))) |
| 2618 | { | 2620 | { |
| @@ -2776,9 +2778,21 @@ merge_face_ref (struct window *w, | |||
| 2776 | { | 2778 | { |
| 2777 | /* This is not really very useful; it's just like a | 2779 | /* This is not really very useful; it's just like a |
| 2778 | normal face reference. */ | 2780 | normal face reference. */ |
| 2779 | if (! merge_face_ref (w, f, value, to, | 2781 | if (attr_filter_passed) |
| 2780 | err_msgs, named_merge_points, | 2782 | { |
| 2781 | attr_filter)) | 2783 | /* We already know that this face was tested |
| 2784 | against attr_filter and was found applicable, | ||
| 2785 | so don't pass attr_filter to merge_face_ref. | ||
| 2786 | This is for when a face is specified like | ||
| 2787 | (:inherit FACE :extend t), but the parent | ||
| 2788 | FACE itself doesn't specify :extend. */ | ||
| 2789 | if (! merge_face_ref (w, f, value, to, | ||
| 2790 | err_msgs, named_merge_points, 0)) | ||
| 2791 | err = true; | ||
| 2792 | } | ||
| 2793 | else if (! merge_face_ref (w, f, value, to, | ||
| 2794 | err_msgs, named_merge_points, | ||
| 2795 | attr_filter)) | ||
| 2782 | err = true; | 2796 | err = true; |
| 2783 | } | 2797 | } |
| 2784 | else if (EQ (keyword, QCextend)) | 2798 | else if (EQ (keyword, QCextend)) |
diff --git a/src/xwidget.c b/src/xwidget.c index 0347f1e6483..c61f5bef88d 100644 --- a/src/xwidget.c +++ b/src/xwidget.c | |||
| @@ -23,13 +23,21 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | |||
| 23 | 23 | ||
| 24 | #include "lisp.h" | 24 | #include "lisp.h" |
| 25 | #include "blockinput.h" | 25 | #include "blockinput.h" |
| 26 | #include "dispextern.h" | ||
| 26 | #include "frame.h" | 27 | #include "frame.h" |
| 27 | #include "keyboard.h" | 28 | #include "keyboard.h" |
| 28 | #include "gtkutil.h" | 29 | #include "gtkutil.h" |
| 29 | #include "sysstdio.h" | 30 | #include "sysstdio.h" |
| 31 | #include "termhooks.h" | ||
| 32 | #include "window.h" | ||
| 30 | 33 | ||
| 34 | /* Include xwidget bottom end headers. */ | ||
| 35 | #ifdef USE_GTK | ||
| 31 | #include <webkit2/webkit2.h> | 36 | #include <webkit2/webkit2.h> |
| 32 | #include <JavaScriptCore/JavaScript.h> | 37 | #include <JavaScriptCore/JavaScript.h> |
| 38 | #elif defined NS_IMPL_COCOA | ||
| 39 | #include "nsxwidget.h" | ||
| 40 | #endif | ||
| 33 | 41 | ||
| 34 | static struct xwidget * | 42 | static struct xwidget * |
| 35 | allocate_xwidget (void) | 43 | allocate_xwidget (void) |
| @@ -48,6 +56,7 @@ allocate_xwidget_view (void) | |||
| 48 | 56 | ||
| 49 | static struct xwidget_view *xwidget_view_lookup (struct xwidget *, | 57 | static struct xwidget_view *xwidget_view_lookup (struct xwidget *, |
| 50 | struct window *); | 58 | struct window *); |
| 59 | #ifdef USE_GTK | ||
| 51 | static void webkit_view_load_changed_cb (WebKitWebView *, | 60 | static void webkit_view_load_changed_cb (WebKitWebView *, |
| 52 | WebKitLoadEvent, | 61 | WebKitLoadEvent, |
| 53 | gpointer); | 62 | gpointer); |
| @@ -61,6 +70,7 @@ webkit_decide_policy_cb (WebKitWebView *, | |||
| 61 | WebKitPolicyDecision *, | 70 | WebKitPolicyDecision *, |
| 62 | WebKitPolicyDecisionType, | 71 | WebKitPolicyDecisionType, |
| 63 | gpointer); | 72 | gpointer); |
| 73 | #endif | ||
| 64 | 74 | ||
| 65 | 75 | ||
| 66 | DEFUN ("make-xwidget", | 76 | DEFUN ("make-xwidget", |
| @@ -78,8 +88,10 @@ Returns the newly constructed xwidget, or nil if construction fails. */) | |||
| 78 | Lisp_Object title, Lisp_Object width, Lisp_Object height, | 88 | Lisp_Object title, Lisp_Object width, Lisp_Object height, |
| 79 | Lisp_Object arguments, Lisp_Object buffer) | 89 | Lisp_Object arguments, Lisp_Object buffer) |
| 80 | { | 90 | { |
| 91 | #ifdef USE_GTK | ||
| 81 | if (!xg_gtk_initialized) | 92 | if (!xg_gtk_initialized) |
| 82 | error ("make-xwidget: GTK has not been initialized"); | 93 | error ("make-xwidget: GTK has not been initialized"); |
| 94 | #endif | ||
| 83 | CHECK_SYMBOL (type); | 95 | CHECK_SYMBOL (type); |
| 84 | CHECK_FIXNAT (width); | 96 | CHECK_FIXNAT (width); |
| 85 | CHECK_FIXNAT (height); | 97 | CHECK_FIXNAT (height); |
| @@ -94,10 +106,11 @@ Returns the newly constructed xwidget, or nil if construction fails. */) | |||
| 94 | xw->kill_without_query = false; | 106 | xw->kill_without_query = false; |
| 95 | XSETXWIDGET (val, xw); | 107 | XSETXWIDGET (val, xw); |
| 96 | Vxwidget_list = Fcons (val, Vxwidget_list); | 108 | Vxwidget_list = Fcons (val, Vxwidget_list); |
| 97 | xw->widgetwindow_osr = NULL; | ||
| 98 | xw->widget_osr = NULL; | ||
| 99 | xw->plist = Qnil; | 109 | xw->plist = Qnil; |
| 100 | 110 | ||
| 111 | #ifdef USE_GTK | ||
| 112 | xw->widgetwindow_osr = NULL; | ||
| 113 | xw->widget_osr = NULL; | ||
| 101 | if (EQ (xw->type, Qwebkit)) | 114 | if (EQ (xw->type, Qwebkit)) |
| 102 | { | 115 | { |
| 103 | block_input (); | 116 | block_input (); |
| @@ -152,6 +165,9 @@ Returns the newly constructed xwidget, or nil if construction fails. */) | |||
| 152 | 165 | ||
| 153 | unblock_input (); | 166 | unblock_input (); |
| 154 | } | 167 | } |
| 168 | #elif defined NS_IMPL_COCOA | ||
| 169 | nsxwidget_init (xw); | ||
| 170 | #endif | ||
| 155 | 171 | ||
| 156 | return val; | 172 | return val; |
| 157 | } | 173 | } |
| @@ -187,6 +203,7 @@ xwidget_hidden (struct xwidget_view *xv) | |||
| 187 | return xv->hidden; | 203 | return xv->hidden; |
| 188 | } | 204 | } |
| 189 | 205 | ||
| 206 | #ifdef USE_GTK | ||
| 190 | static void | 207 | static void |
| 191 | xwidget_show_view (struct xwidget_view *xv) | 208 | xwidget_show_view (struct xwidget_view *xv) |
| 192 | { | 209 | { |
| @@ -220,13 +237,14 @@ offscreen_damage_event (GtkWidget *widget, GdkEvent *event, | |||
| 220 | if (GTK_IS_WIDGET (xv_widget)) | 237 | if (GTK_IS_WIDGET (xv_widget)) |
| 221 | gtk_widget_queue_draw (GTK_WIDGET (xv_widget)); | 238 | gtk_widget_queue_draw (GTK_WIDGET (xv_widget)); |
| 222 | else | 239 | else |
| 223 | printf ("Warning, offscreen_damage_event received invalid xv pointer:%p\n", | 240 | message ("Warning, offscreen_damage_event received invalid xv pointer:%p\n", |
| 224 | xv_widget); | 241 | xv_widget); |
| 225 | 242 | ||
| 226 | return FALSE; | 243 | return FALSE; |
| 227 | } | 244 | } |
| 245 | #endif /* USE_GTK */ | ||
| 228 | 246 | ||
| 229 | static void | 247 | void |
| 230 | store_xwidget_event_string (struct xwidget *xw, const char *eventname, | 248 | store_xwidget_event_string (struct xwidget *xw, const char *eventname, |
| 231 | const char *eventstr) | 249 | const char *eventstr) |
| 232 | { | 250 | { |
| @@ -240,7 +258,27 @@ store_xwidget_event_string (struct xwidget *xw, const char *eventname, | |||
| 240 | kbd_buffer_store_event (&event); | 258 | kbd_buffer_store_event (&event); |
| 241 | } | 259 | } |
| 242 | 260 | ||
| 243 | static void | 261 | void |
| 262 | store_xwidget_download_callback_event (struct xwidget *xw, | ||
| 263 | const char *url, | ||
| 264 | const char *mimetype, | ||
| 265 | const char *filename) | ||
| 266 | { | ||
| 267 | struct input_event event; | ||
| 268 | Lisp_Object xwl; | ||
| 269 | XSETXWIDGET (xwl, xw); | ||
| 270 | EVENT_INIT (event); | ||
| 271 | event.kind = XWIDGET_EVENT; | ||
| 272 | event.frame_or_window = Qnil; | ||
| 273 | event.arg = list5 (intern ("download-callback"), | ||
| 274 | xwl, | ||
| 275 | build_string (url), | ||
| 276 | build_string (mimetype), | ||
| 277 | build_string (filename)); | ||
| 278 | kbd_buffer_store_event (&event); | ||
| 279 | } | ||
| 280 | |||
| 281 | void | ||
| 244 | store_xwidget_js_callback_event (struct xwidget *xw, | 282 | store_xwidget_js_callback_event (struct xwidget *xw, |
| 245 | Lisp_Object proc, | 283 | Lisp_Object proc, |
| 246 | Lisp_Object argument) | 284 | Lisp_Object argument) |
| @@ -256,6 +294,7 @@ store_xwidget_js_callback_event (struct xwidget *xw, | |||
| 256 | } | 294 | } |
| 257 | 295 | ||
| 258 | 296 | ||
| 297 | #ifdef USE_GTK | ||
| 259 | void | 298 | void |
| 260 | webkit_view_load_changed_cb (WebKitWebView *webkitwebview, | 299 | webkit_view_load_changed_cb (WebKitWebView *webkitwebview, |
| 261 | WebKitLoadEvent load_event, | 300 | WebKitLoadEvent load_event, |
| @@ -486,6 +525,7 @@ xwidget_osr_event_set_embedder (GtkWidget *widget, GdkEvent *event, | |||
| 486 | gtk_widget_get_window (xv->widget)); | 525 | gtk_widget_get_window (xv->widget)); |
| 487 | return FALSE; | 526 | return FALSE; |
| 488 | } | 527 | } |
| 528 | #endif /* USE_GTK */ | ||
| 489 | 529 | ||
| 490 | 530 | ||
| 491 | /* Initializes and does initial placement of an xwidget view on screen. */ | 531 | /* Initializes and does initial placement of an xwidget view on screen. */ |
| @@ -495,8 +535,10 @@ xwidget_init_view (struct xwidget *xww, | |||
| 495 | int x, int y) | 535 | int x, int y) |
| 496 | { | 536 | { |
| 497 | 537 | ||
| 538 | #ifdef USE_GTK | ||
| 498 | if (!xg_gtk_initialized) | 539 | if (!xg_gtk_initialized) |
| 499 | error ("xwidget_init_view: GTK has not been initialized"); | 540 | error ("xwidget_init_view: GTK has not been initialized"); |
| 541 | #endif | ||
| 500 | 542 | ||
| 501 | struct xwidget_view *xv = allocate_xwidget_view (); | 543 | struct xwidget_view *xv = allocate_xwidget_view (); |
| 502 | Lisp_Object val; | 544 | Lisp_Object val; |
| @@ -507,6 +549,7 @@ xwidget_init_view (struct xwidget *xww, | |||
| 507 | XSETWINDOW (xv->w, s->w); | 549 | XSETWINDOW (xv->w, s->w); |
| 508 | XSETXWIDGET (xv->model, xww); | 550 | XSETXWIDGET (xv->model, xww); |
| 509 | 551 | ||
| 552 | #ifdef USE_GTK | ||
| 510 | if (EQ (xww->type, Qwebkit)) | 553 | if (EQ (xww->type, Qwebkit)) |
| 511 | { | 554 | { |
| 512 | xv->widget = gtk_drawing_area_new (); | 555 | xv->widget = gtk_drawing_area_new (); |
| @@ -564,6 +607,10 @@ xwidget_init_view (struct xwidget *xww, | |||
| 564 | xv->x = x; | 607 | xv->x = x; |
| 565 | xv->y = y; | 608 | xv->y = y; |
| 566 | gtk_widget_show_all (xv->widgetwindow); | 609 | gtk_widget_show_all (xv->widgetwindow); |
| 610 | #elif defined NS_IMPL_COCOA | ||
| 611 | nsxwidget_init_view (xv, xww, s, x, y); | ||
| 612 | nsxwidget_resize_view(xv, xww->width, xww->height); | ||
| 613 | #endif | ||
| 567 | 614 | ||
| 568 | return xv; | 615 | return xv; |
| 569 | } | 616 | } |
| @@ -576,6 +623,7 @@ x_draw_xwidget_glyph_string (struct glyph_string *s) | |||
| 576 | initialization. */ | 623 | initialization. */ |
| 577 | struct xwidget *xww = s->xwidget; | 624 | struct xwidget *xww = s->xwidget; |
| 578 | struct xwidget_view *xv = xwidget_view_lookup (xww, s->w); | 625 | struct xwidget_view *xv = xwidget_view_lookup (xww, s->w); |
| 626 | int text_area_x, text_area_y, text_area_width, text_area_height; | ||
| 579 | int clip_right; | 627 | int clip_right; |
| 580 | int clip_bottom; | 628 | int clip_bottom; |
| 581 | int clip_top; | 629 | int clip_top; |
| @@ -587,13 +635,47 @@ x_draw_xwidget_glyph_string (struct glyph_string *s) | |||
| 587 | /* Do initialization here in the display loop because there is no | 635 | /* Do initialization here in the display loop because there is no |
| 588 | other time to know things like window placement etc. Do not | 636 | other time to know things like window placement etc. Do not |
| 589 | create a new view if we have found one that is usable. */ | 637 | create a new view if we have found one that is usable. */ |
| 638 | #ifdef USE_GTK | ||
| 590 | if (!xv) | 639 | if (!xv) |
| 591 | xv = xwidget_init_view (xww, s, x, y); | 640 | xv = xwidget_init_view (xww, s, x, y); |
| 592 | 641 | #elif defined NS_IMPL_COCOA | |
| 593 | int text_area_x, text_area_y, text_area_width, text_area_height; | 642 | if (!xv) |
| 643 | { | ||
| 644 | /* Enforce 1 to 1, model and view for macOS Cocoa webkit2. */ | ||
| 645 | if (xww->xv) | ||
| 646 | { | ||
| 647 | if (xwidget_hidden (xww->xv)) | ||
| 648 | { | ||
| 649 | Lisp_Object xvl; | ||
| 650 | XSETXWIDGET_VIEW (xvl, xww->xv); | ||
| 651 | Fdelete_xwidget_view (xvl); | ||
| 652 | } | ||
| 653 | else | ||
| 654 | { | ||
| 655 | message ("You can't share an xwidget (webkit2) among windows."); | ||
| 656 | return; | ||
| 657 | } | ||
| 658 | } | ||
| 659 | xv = xwidget_init_view (xww, s, x, y); | ||
| 660 | } | ||
| 661 | #endif | ||
| 594 | 662 | ||
| 595 | window_box (s->w, TEXT_AREA, &text_area_x, &text_area_y, | 663 | window_box (s->w, TEXT_AREA, &text_area_x, &text_area_y, |
| 596 | &text_area_width, &text_area_height); | 664 | &text_area_width, &text_area_height); |
| 665 | |||
| 666 | /* Resize xwidget webkit if its container window size is changed in | ||
| 667 | some ways, for example, a buffer became hidden in small split | ||
| 668 | window, then it can appear front in merged whole window. */ | ||
| 669 | if (EQ (xww->type, Qwebkit) | ||
| 670 | && (xww->width != text_area_width || xww->height != text_area_height)) | ||
| 671 | { | ||
| 672 | Lisp_Object xwl; | ||
| 673 | XSETXWIDGET (xwl, xww); | ||
| 674 | Fxwidget_resize (xwl, | ||
| 675 | make_int (text_area_width), | ||
| 676 | make_int (text_area_height)); | ||
| 677 | } | ||
| 678 | |||
| 597 | clip_left = max (0, text_area_x - x); | 679 | clip_left = max (0, text_area_x - x); |
| 598 | clip_right = max (clip_left, | 680 | clip_right = max (clip_left, |
| 599 | min (xww->width, text_area_x + text_area_width - x)); | 681 | min (xww->width, text_area_x + text_area_width - x)); |
| @@ -616,8 +698,14 @@ x_draw_xwidget_glyph_string (struct glyph_string *s) | |||
| 616 | 698 | ||
| 617 | /* Has it moved? */ | 699 | /* Has it moved? */ |
| 618 | if (moved) | 700 | if (moved) |
| 619 | gtk_fixed_move (GTK_FIXED (FRAME_GTK_WIDGET (s->f)), | 701 | { |
| 620 | xv->widgetwindow, x + clip_left, y + clip_top); | 702 | #ifdef USE_GTK |
| 703 | gtk_fixed_move (GTK_FIXED (FRAME_GTK_WIDGET (s->f)), | ||
| 704 | xv->widgetwindow, x + clip_left, y + clip_top); | ||
| 705 | #elif defined NS_IMPL_COCOA | ||
| 706 | nsxwidget_move_view (xv, x + clip_left, y + clip_top); | ||
| 707 | #endif | ||
| 708 | } | ||
| 621 | 709 | ||
| 622 | /* Clip the widget window if some parts happen to be outside | 710 | /* Clip the widget window if some parts happen to be outside |
| 623 | drawable area. An Emacs window is not a gtk window. A gtk window | 711 | drawable area. An Emacs window is not a gtk window. A gtk window |
| @@ -628,10 +716,16 @@ x_draw_xwidget_glyph_string (struct glyph_string *s) | |||
| 628 | || xv->clip_bottom != clip_bottom | 716 | || xv->clip_bottom != clip_bottom |
| 629 | || xv->clip_top != clip_top || xv->clip_left != clip_left) | 717 | || xv->clip_top != clip_top || xv->clip_left != clip_left) |
| 630 | { | 718 | { |
| 719 | #ifdef USE_GTK | ||
| 631 | gtk_widget_set_size_request (xv->widgetwindow, clip_right - clip_left, | 720 | gtk_widget_set_size_request (xv->widgetwindow, clip_right - clip_left, |
| 632 | clip_bottom - clip_top); | 721 | clip_bottom - clip_top); |
| 633 | gtk_fixed_move (GTK_FIXED (xv->widgetwindow), xv->widget, -clip_left, | 722 | gtk_fixed_move (GTK_FIXED (xv->widgetwindow), xv->widget, -clip_left, |
| 634 | -clip_top); | 723 | -clip_top); |
| 724 | #elif defined NS_IMPL_COCOA | ||
| 725 | nsxwidget_resize_view (xv, clip_right - clip_left, | ||
| 726 | clip_bottom - clip_top); | ||
| 727 | nsxwidget_move_widget_in_view (xv, -clip_left, -clip_top); | ||
| 728 | #endif | ||
| 635 | 729 | ||
| 636 | xv->clip_right = clip_right; | 730 | xv->clip_right = clip_right; |
| 637 | xv->clip_bottom = clip_bottom; | 731 | xv->clip_bottom = clip_bottom; |
| @@ -645,22 +739,66 @@ x_draw_xwidget_glyph_string (struct glyph_string *s) | |||
| 645 | xwidgets background. It's just a visual glitch though. */ | 739 | xwidgets background. It's just a visual glitch though. */ |
| 646 | if (!xwidget_hidden (xv)) | 740 | if (!xwidget_hidden (xv)) |
| 647 | { | 741 | { |
| 742 | #ifdef USE_GTK | ||
| 648 | gtk_widget_queue_draw (xv->widgetwindow); | 743 | gtk_widget_queue_draw (xv->widgetwindow); |
| 649 | gtk_widget_queue_draw (xv->widget); | 744 | gtk_widget_queue_draw (xv->widget); |
| 745 | #elif defined NS_IMPL_COCOA | ||
| 746 | nsxwidget_set_needsdisplay (xv); | ||
| 747 | #endif | ||
| 650 | } | 748 | } |
| 651 | } | 749 | } |
| 652 | 750 | ||
| 653 | /* Macro that checks WEBKIT_IS_WEB_VIEW (xw->widget_osr) first. */ | 751 | static bool |
| 752 | xwidget_is_web_view (struct xwidget *xw) | ||
| 753 | { | ||
| 754 | #ifdef USE_GTK | ||
| 755 | return xw->widget_osr != NULL && WEBKIT_IS_WEB_VIEW (xw->widget_osr); | ||
| 756 | #elif defined NS_IMPL_COCOA | ||
| 757 | return nsxwidget_is_web_view (xw); | ||
| 758 | #endif | ||
| 759 | } | ||
| 760 | |||
| 761 | /* Macro that checks xwidget hold webkit web view first. */ | ||
| 654 | #define WEBKIT_FN_INIT() \ | 762 | #define WEBKIT_FN_INIT() \ |
| 655 | CHECK_XWIDGET (xwidget); \ | 763 | CHECK_XWIDGET (xwidget); \ |
| 656 | struct xwidget *xw = XXWIDGET (xwidget); \ | 764 | struct xwidget *xw = XXWIDGET (xwidget); \ |
| 657 | if (!xw->widget_osr || !WEBKIT_IS_WEB_VIEW (xw->widget_osr)) \ | 765 | if (!xwidget_is_web_view (xw)) \ |
| 658 | { \ | 766 | { \ |
| 659 | fputs ("ERROR xw->widget_osr does not hold a webkit instance\n", \ | 767 | fputs ("ERROR xw->widget_osr does not hold a webkit instance\n", \ |
| 660 | stdout); \ | 768 | stdout); \ |
| 661 | return Qnil; \ | 769 | return Qnil; \ |
| 662 | } | 770 | } |
| 663 | 771 | ||
| 772 | DEFUN ("xwidget-webkit-uri", | ||
| 773 | Fxwidget_webkit_uri, Sxwidget_webkit_uri, | ||
| 774 | 1, 1, 0, | ||
| 775 | doc: /* Get the current URL of XWIDGET webkit. */) | ||
| 776 | (Lisp_Object xwidget) | ||
| 777 | { | ||
| 778 | WEBKIT_FN_INIT (); | ||
| 779 | #ifdef USE_GTK | ||
| 780 | WebKitWebView *wkwv = WEBKIT_WEB_VIEW (xw->widget_osr); | ||
| 781 | return build_string (webkit_web_view_get_uri (wkwv)); | ||
| 782 | #elif defined NS_IMPL_COCOA | ||
| 783 | return nsxwidget_webkit_uri (xw); | ||
| 784 | #endif | ||
| 785 | } | ||
| 786 | |||
| 787 | DEFUN ("xwidget-webkit-title", | ||
| 788 | Fxwidget_webkit_title, Sxwidget_webkit_title, | ||
| 789 | 1, 1, 0, | ||
| 790 | doc: /* Get the current title of XWIDGET webkit. */) | ||
| 791 | (Lisp_Object xwidget) | ||
| 792 | { | ||
| 793 | WEBKIT_FN_INIT (); | ||
| 794 | #ifdef USE_GTK | ||
| 795 | WebKitWebView *wkwv = WEBKIT_WEB_VIEW (xw->widget_osr); | ||
| 796 | return build_string (webkit_web_view_get_title (wkwv)); | ||
| 797 | #elif defined NS_IMPL_COCOA | ||
| 798 | return nsxwidget_webkit_title (xw); | ||
| 799 | #endif | ||
| 800 | } | ||
| 801 | |||
| 664 | DEFUN ("xwidget-webkit-goto-uri", | 802 | DEFUN ("xwidget-webkit-goto-uri", |
| 665 | Fxwidget_webkit_goto_uri, Sxwidget_webkit_goto_uri, | 803 | Fxwidget_webkit_goto_uri, Sxwidget_webkit_goto_uri, |
| 666 | 2, 2, 0, | 804 | 2, 2, 0, |
| @@ -670,7 +808,36 @@ DEFUN ("xwidget-webkit-goto-uri", | |||
| 670 | WEBKIT_FN_INIT (); | 808 | WEBKIT_FN_INIT (); |
| 671 | CHECK_STRING (uri); | 809 | CHECK_STRING (uri); |
| 672 | uri = ENCODE_FILE (uri); | 810 | uri = ENCODE_FILE (uri); |
| 811 | #ifdef USE_GTK | ||
| 673 | webkit_web_view_load_uri (WEBKIT_WEB_VIEW (xw->widget_osr), SSDATA (uri)); | 812 | webkit_web_view_load_uri (WEBKIT_WEB_VIEW (xw->widget_osr), SSDATA (uri)); |
| 813 | #elif defined NS_IMPL_COCOA | ||
| 814 | nsxwidget_webkit_goto_uri (xw, SSDATA (uri)); | ||
| 815 | #endif | ||
| 816 | return Qnil; | ||
| 817 | } | ||
| 818 | |||
| 819 | DEFUN ("xwidget-webkit-goto-history", | ||
| 820 | Fxwidget_webkit_goto_history, Sxwidget_webkit_goto_history, | ||
| 821 | 2, 2, 0, | ||
| 822 | doc: /* Make the XWIDGET webkit load REL-POS (-1, 0, 1) page in browse history. */) | ||
| 823 | (Lisp_Object xwidget, Lisp_Object rel_pos) | ||
| 824 | { | ||
| 825 | WEBKIT_FN_INIT (); | ||
| 826 | /* Should be one of -1, 0, 1 */ | ||
| 827 | if (XFIXNUM (rel_pos) < -1 || XFIXNUM (rel_pos) > 1) | ||
| 828 | args_out_of_range_3 (rel_pos, make_fixnum (-1), make_fixnum (1)); | ||
| 829 | |||
| 830 | #ifdef USE_GTK | ||
| 831 | WebKitWebView *wkwv = WEBKIT_WEB_VIEW (xw->widget_osr); | ||
| 832 | switch (XFIXNAT (rel_pos)) | ||
| 833 | { | ||
| 834 | case -1: webkit_web_view_go_back (wkwv); break; | ||
| 835 | case 0: webkit_web_view_reload (wkwv); break; | ||
| 836 | case 1: webkit_web_view_go_forward (wkwv); break; | ||
| 837 | } | ||
| 838 | #elif defined NS_IMPL_COCOA | ||
| 839 | nsxwidget_webkit_goto_history (xw, XFIXNAT (rel_pos)); | ||
| 840 | #endif | ||
| 674 | return Qnil; | 841 | return Qnil; |
| 675 | } | 842 | } |
| 676 | 843 | ||
| @@ -684,14 +851,19 @@ DEFUN ("xwidget-webkit-zoom", | |||
| 684 | if (FLOATP (factor)) | 851 | if (FLOATP (factor)) |
| 685 | { | 852 | { |
| 686 | double zoom_change = XFLOAT_DATA (factor); | 853 | double zoom_change = XFLOAT_DATA (factor); |
| 854 | #ifdef USE_GTK | ||
| 687 | webkit_web_view_set_zoom_level | 855 | webkit_web_view_set_zoom_level |
| 688 | (WEBKIT_WEB_VIEW (xw->widget_osr), | 856 | (WEBKIT_WEB_VIEW (xw->widget_osr), |
| 689 | webkit_web_view_get_zoom_level | 857 | webkit_web_view_get_zoom_level |
| 690 | (WEBKIT_WEB_VIEW (xw->widget_osr)) + zoom_change); | 858 | (WEBKIT_WEB_VIEW (xw->widget_osr)) + zoom_change); |
| 859 | #elif defined NS_IMPL_COCOA | ||
| 860 | nsxwidget_webkit_zoom (xw, zoom_change); | ||
| 861 | #endif | ||
| 691 | } | 862 | } |
| 692 | return Qnil; | 863 | return Qnil; |
| 693 | } | 864 | } |
| 694 | 865 | ||
| 866 | #ifdef USE_GTK | ||
| 695 | /* Save script and fun in the script/callback save vector and return | 867 | /* Save script and fun in the script/callback save vector and return |
| 696 | its index. */ | 868 | its index. */ |
| 697 | static ptrdiff_t | 869 | static ptrdiff_t |
| @@ -713,6 +885,7 @@ save_script_callback (struct xwidget *xw, Lisp_Object script, Lisp_Object fun) | |||
| 713 | ASET (cbs, idx, Fcons (make_mint_ptr (xlispstrdup (script)), fun)); | 885 | ASET (cbs, idx, Fcons (make_mint_ptr (xlispstrdup (script)), fun)); |
| 714 | return idx; | 886 | return idx; |
| 715 | } | 887 | } |
| 888 | #endif | ||
| 716 | 889 | ||
| 717 | DEFUN ("xwidget-webkit-execute-script", | 890 | DEFUN ("xwidget-webkit-execute-script", |
| 718 | Fxwidget_webkit_execute_script, Sxwidget_webkit_execute_script, | 891 | Fxwidget_webkit_execute_script, Sxwidget_webkit_execute_script, |
| @@ -729,6 +902,7 @@ argument procedure FUN.*/) | |||
| 729 | 902 | ||
| 730 | script = ENCODE_SYSTEM (script); | 903 | script = ENCODE_SYSTEM (script); |
| 731 | 904 | ||
| 905 | #ifdef USE_GTK | ||
| 732 | /* Protect script and fun during GC. */ | 906 | /* Protect script and fun during GC. */ |
| 733 | intptr_t idx = save_script_callback (xw, script, fun); | 907 | intptr_t idx = save_script_callback (xw, script, fun); |
| 734 | 908 | ||
| @@ -742,6 +916,9 @@ argument procedure FUN.*/) | |||
| 742 | NULL, /* cancelable */ | 916 | NULL, /* cancelable */ |
| 743 | webkit_javascript_finished_cb, | 917 | webkit_javascript_finished_cb, |
| 744 | (gpointer) idx); | 918 | (gpointer) idx); |
| 919 | #elif defined NS_IMPL_COCOA | ||
| 920 | nsxwidget_webkit_execute_script (xw, SSDATA (script), fun); | ||
| 921 | #endif | ||
| 745 | return Qnil; | 922 | return Qnil; |
| 746 | } | 923 | } |
| 747 | 924 | ||
| @@ -758,6 +935,7 @@ DEFUN ("xwidget-resize", Fxwidget_resize, Sxwidget_resize, 3, 3, 0, | |||
| 758 | xw->height = h; | 935 | xw->height = h; |
| 759 | 936 | ||
| 760 | /* If there is an offscreen widget resize it first. */ | 937 | /* If there is an offscreen widget resize it first. */ |
| 938 | #ifdef USE_GTK | ||
| 761 | if (xw->widget_osr) | 939 | if (xw->widget_osr) |
| 762 | { | 940 | { |
| 763 | gtk_window_resize (GTK_WINDOW (xw->widgetwindow_osr), xw->width, | 941 | gtk_window_resize (GTK_WINDOW (xw->widgetwindow_osr), xw->width, |
| @@ -766,6 +944,9 @@ DEFUN ("xwidget-resize", Fxwidget_resize, Sxwidget_resize, 3, 3, 0, | |||
| 766 | gtk_widget_set_size_request (GTK_WIDGET (xw->widget_osr), xw->width, | 944 | gtk_widget_set_size_request (GTK_WIDGET (xw->widget_osr), xw->width, |
| 767 | xw->height); | 945 | xw->height); |
| 768 | } | 946 | } |
| 947 | #elif defined NS_IMPL_COCOA | ||
| 948 | nsxwidget_resize (xw); | ||
| 949 | #endif | ||
| 769 | 950 | ||
| 770 | for (Lisp_Object tail = Vxwidget_view_list; CONSP (tail); tail = XCDR (tail)) | 951 | for (Lisp_Object tail = Vxwidget_view_list; CONSP (tail); tail = XCDR (tail)) |
| 771 | { | 952 | { |
| @@ -773,8 +954,14 @@ DEFUN ("xwidget-resize", Fxwidget_resize, Sxwidget_resize, 3, 3, 0, | |||
| 773 | { | 954 | { |
| 774 | struct xwidget_view *xv = XXWIDGET_VIEW (XCAR (tail)); | 955 | struct xwidget_view *xv = XXWIDGET_VIEW (XCAR (tail)); |
| 775 | if (XXWIDGET (xv->model) == xw) | 956 | if (XXWIDGET (xv->model) == xw) |
| 957 | { | ||
| 958 | #ifdef USE_GTK | ||
| 776 | gtk_widget_set_size_request (GTK_WIDGET (xv->widget), xw->width, | 959 | gtk_widget_set_size_request (GTK_WIDGET (xv->widget), xw->width, |
| 777 | xw->height); | 960 | xw->height); |
| 961 | #elif defined NS_IMPL_COCOA | ||
| 962 | nsxwidget_resize_view(xv, xw->width, xw->height); | ||
| 963 | #endif | ||
| 964 | } | ||
| 778 | } | 965 | } |
| 779 | } | 966 | } |
| 780 | 967 | ||
| @@ -793,9 +980,13 @@ Emacs allocated area accordingly. */) | |||
| 793 | (Lisp_Object xwidget) | 980 | (Lisp_Object xwidget) |
| 794 | { | 981 | { |
| 795 | CHECK_XWIDGET (xwidget); | 982 | CHECK_XWIDGET (xwidget); |
| 983 | #ifdef USE_GTK | ||
| 796 | GtkRequisition requisition; | 984 | GtkRequisition requisition; |
| 797 | gtk_widget_size_request (XXWIDGET (xwidget)->widget_osr, &requisition); | 985 | gtk_widget_size_request (XXWIDGET (xwidget)->widget_osr, &requisition); |
| 798 | return list2i (requisition.width, requisition.height); | 986 | return list2i (requisition.width, requisition.height); |
| 987 | #elif defined NS_IMPL_COCOA | ||
| 988 | return nsxwidget_get_size (XXWIDGET (xwidget)); | ||
| 989 | #endif | ||
| 799 | } | 990 | } |
| 800 | 991 | ||
| 801 | DEFUN ("xwidgetp", | 992 | DEFUN ("xwidgetp", |
| @@ -872,14 +1063,19 @@ DEFUN ("delete-xwidget-view", | |||
| 872 | { | 1063 | { |
| 873 | CHECK_XWIDGET_VIEW (xwidget_view); | 1064 | CHECK_XWIDGET_VIEW (xwidget_view); |
| 874 | struct xwidget_view *xv = XXWIDGET_VIEW (xwidget_view); | 1065 | struct xwidget_view *xv = XXWIDGET_VIEW (xwidget_view); |
| 1066 | #ifdef USE_GTK | ||
| 875 | gtk_widget_destroy (xv->widgetwindow); | 1067 | gtk_widget_destroy (xv->widgetwindow); |
| 876 | Vxwidget_view_list = Fdelq (xwidget_view, Vxwidget_view_list); | ||
| 877 | /* xv->model still has signals pointing to the view. There can be | 1068 | /* xv->model still has signals pointing to the view. There can be |
| 878 | several views. Find the matching signals and delete them all. */ | 1069 | several views. Find the matching signals and delete them all. */ |
| 879 | g_signal_handlers_disconnect_matched (XXWIDGET (xv->model)->widgetwindow_osr, | 1070 | g_signal_handlers_disconnect_matched (XXWIDGET (xv->model)->widgetwindow_osr, |
| 880 | G_SIGNAL_MATCH_DATA, | 1071 | G_SIGNAL_MATCH_DATA, |
| 881 | 0, 0, 0, 0, | 1072 | 0, 0, 0, 0, |
| 882 | xv->widget); | 1073 | xv->widget); |
| 1074 | #elif defined NS_IMPL_COCOA | ||
| 1075 | nsxwidget_delete_view (xv); | ||
| 1076 | #endif | ||
| 1077 | |||
| 1078 | Vxwidget_view_list = Fdelq (xwidget_view, Vxwidget_view_list); | ||
| 883 | return Qnil; | 1079 | return Qnil; |
| 884 | } | 1080 | } |
| 885 | 1081 | ||
| @@ -985,7 +1181,10 @@ syms_of_xwidget (void) | |||
| 985 | defsubr (&Sxwidget_query_on_exit_flag); | 1181 | defsubr (&Sxwidget_query_on_exit_flag); |
| 986 | defsubr (&Sset_xwidget_query_on_exit_flag); | 1182 | defsubr (&Sset_xwidget_query_on_exit_flag); |
| 987 | 1183 | ||
| 1184 | defsubr (&Sxwidget_webkit_uri); | ||
| 1185 | defsubr (&Sxwidget_webkit_title); | ||
| 988 | defsubr (&Sxwidget_webkit_goto_uri); | 1186 | defsubr (&Sxwidget_webkit_goto_uri); |
| 1187 | defsubr (&Sxwidget_webkit_goto_history); | ||
| 989 | defsubr (&Sxwidget_webkit_zoom); | 1188 | defsubr (&Sxwidget_webkit_zoom); |
| 990 | defsubr (&Sxwidget_webkit_execute_script); | 1189 | defsubr (&Sxwidget_webkit_execute_script); |
| 991 | DEFSYM (Qwebkit, "webkit"); | 1190 | DEFSYM (Qwebkit, "webkit"); |
| @@ -1156,11 +1355,19 @@ xwidget_end_redisplay (struct window *w, struct glyph_matrix *matrix) | |||
| 1156 | xwidget_end_redisplay (w->current_matrix); */ | 1355 | xwidget_end_redisplay (w->current_matrix); */ |
| 1157 | struct xwidget_view *xv | 1356 | struct xwidget_view *xv |
| 1158 | = xwidget_view_lookup (glyph->u.xwidget, w); | 1357 | = xwidget_view_lookup (glyph->u.xwidget, w); |
| 1358 | #ifdef USE_GTK | ||
| 1159 | /* FIXME: Is it safe to assume xwidget_view_lookup | 1359 | /* FIXME: Is it safe to assume xwidget_view_lookup |
| 1160 | always succeeds here? If so, this comment can be removed. | 1360 | always succeeds here? If so, this comment can be removed. |
| 1161 | If not, the code probably needs fixing. */ | 1361 | If not, the code probably needs fixing. */ |
| 1162 | eassume (xv); | 1362 | eassume (xv); |
| 1163 | xwidget_touch (xv); | 1363 | xwidget_touch (xv); |
| 1364 | #elif defined NS_IMPL_COCOA | ||
| 1365 | /* In NS xwidget, xv can be NULL for the second or | ||
| 1366 | later views for a model, the result of 1 to 1 | ||
| 1367 | model view relation enforcement. */ | ||
| 1368 | if (xv) | ||
| 1369 | xwidget_touch (xv); | ||
| 1370 | #endif | ||
| 1164 | } | 1371 | } |
| 1165 | } | 1372 | } |
| 1166 | } | 1373 | } |
| @@ -1177,9 +1384,21 @@ xwidget_end_redisplay (struct window *w, struct glyph_matrix *matrix) | |||
| 1177 | if (XWINDOW (xv->w) == w) | 1384 | if (XWINDOW (xv->w) == w) |
| 1178 | { | 1385 | { |
| 1179 | if (xwidget_touched (xv)) | 1386 | if (xwidget_touched (xv)) |
| 1180 | xwidget_show_view (xv); | 1387 | { |
| 1388 | #ifdef USE_GTK | ||
| 1389 | xwidget_show_view (xv); | ||
| 1390 | #elif defined NS_IMPL_COCOA | ||
| 1391 | nsxwidget_show_view (xv); | ||
| 1392 | #endif | ||
| 1393 | } | ||
| 1181 | else | 1394 | else |
| 1182 | xwidget_hide_view (xv); | 1395 | { |
| 1396 | #ifdef USE_GTK | ||
| 1397 | xwidget_hide_view (xv); | ||
| 1398 | #elif defined NS_IMPL_COCOA | ||
| 1399 | nsxwidget_hide_view (xv); | ||
| 1400 | #endif | ||
| 1401 | } | ||
| 1183 | } | 1402 | } |
| 1184 | } | 1403 | } |
| 1185 | } | 1404 | } |
| @@ -1198,6 +1417,7 @@ kill_buffer_xwidgets (Lisp_Object buffer) | |||
| 1198 | { | 1417 | { |
| 1199 | CHECK_XWIDGET (xwidget); | 1418 | CHECK_XWIDGET (xwidget); |
| 1200 | struct xwidget *xw = XXWIDGET (xwidget); | 1419 | struct xwidget *xw = XXWIDGET (xwidget); |
| 1420 | #ifdef USE_GTK | ||
| 1201 | if (xw->widget_osr && xw->widgetwindow_osr) | 1421 | if (xw->widget_osr && xw->widgetwindow_osr) |
| 1202 | { | 1422 | { |
| 1203 | gtk_widget_destroy (xw->widget_osr); | 1423 | gtk_widget_destroy (xw->widget_osr); |
| @@ -1211,6 +1431,9 @@ kill_buffer_xwidgets (Lisp_Object buffer) | |||
| 1211 | xfree (xmint_pointer (XCAR (cb))); | 1431 | xfree (xmint_pointer (XCAR (cb))); |
| 1212 | ASET (xw->script_callbacks, idx, Qnil); | 1432 | ASET (xw->script_callbacks, idx, Qnil); |
| 1213 | } | 1433 | } |
| 1434 | #elif defined NS_IMPL_COCOA | ||
| 1435 | nsxwidget_kill (xw); | ||
| 1436 | #endif | ||
| 1214 | } | 1437 | } |
| 1215 | } | 1438 | } |
| 1216 | } | 1439 | } |
diff --git a/src/xwidget.h b/src/xwidget.h index 99fa8bbd612..40ad8ae8334 100644 --- a/src/xwidget.h +++ b/src/xwidget.h | |||
| @@ -29,7 +29,13 @@ struct xwidget_view; | |||
| 29 | struct window; | 29 | struct window; |
| 30 | 30 | ||
| 31 | #ifdef HAVE_XWIDGETS | 31 | #ifdef HAVE_XWIDGETS |
| 32 | # include <gtk/gtk.h> | 32 | |
| 33 | #if defined (USE_GTK) | ||
| 34 | #include <gtk/gtk.h> | ||
| 35 | #elif defined (NS_IMPL_COCOA) && defined (__OBJC__) | ||
| 36 | #import <AppKit/NSView.h> | ||
| 37 | #import "nsxwidget.h" | ||
| 38 | #endif | ||
| 33 | 39 | ||
| 34 | struct xwidget | 40 | struct xwidget |
| 35 | { | 41 | { |
| @@ -54,9 +60,25 @@ struct xwidget | |||
| 54 | int height; | 60 | int height; |
| 55 | int width; | 61 | int width; |
| 56 | 62 | ||
| 63 | #if defined (USE_GTK) | ||
| 57 | /* For offscreen widgets, unused if not osr. */ | 64 | /* For offscreen widgets, unused if not osr. */ |
| 58 | GtkWidget *widget_osr; | 65 | GtkWidget *widget_osr; |
| 59 | GtkWidget *widgetwindow_osr; | 66 | GtkWidget *widgetwindow_osr; |
| 67 | #elif defined (NS_IMPL_COCOA) | ||
| 68 | # ifdef __OBJC__ | ||
| 69 | /* For offscreen widgets, unused if not osr. */ | ||
| 70 | NSView *xwWidget; | ||
| 71 | XwWindow *xwWindow; | ||
| 72 | |||
| 73 | /* Used only for xwidget types (such as webkit2) enforcing 1 to 1 | ||
| 74 | relationship between model and view. */ | ||
| 75 | struct xwidget_view *xv; | ||
| 76 | # else | ||
| 77 | void *xwWidget; | ||
| 78 | void *xwWindow; | ||
| 79 | struct xwidget_view *xv; | ||
| 80 | # endif | ||
| 81 | #endif | ||
| 60 | 82 | ||
| 61 | /* Kill silently if Emacs is exited. */ | 83 | /* Kill silently if Emacs is exited. */ |
| 62 | bool_bf kill_without_query : 1; | 84 | bool_bf kill_without_query : 1; |
| @@ -75,9 +97,20 @@ struct xwidget_view | |||
| 75 | /* The "live" instance isn't drawn. */ | 97 | /* The "live" instance isn't drawn. */ |
| 76 | bool hidden; | 98 | bool hidden; |
| 77 | 99 | ||
| 100 | #if defined (USE_GTK) | ||
| 78 | GtkWidget *widget; | 101 | GtkWidget *widget; |
| 79 | GtkWidget *widgetwindow; | 102 | GtkWidget *widgetwindow; |
| 80 | GtkWidget *emacswindow; | 103 | GtkWidget *emacswindow; |
| 104 | #elif defined (NS_IMPL_COCOA) | ||
| 105 | # ifdef __OBJC__ | ||
| 106 | XvWindow *xvWindow; | ||
| 107 | NSView *emacswindow; | ||
| 108 | # else | ||
| 109 | void *xvWindow; | ||
| 110 | void *emacswindow; | ||
| 111 | # endif | ||
| 112 | #endif | ||
| 113 | |||
| 81 | int x; | 114 | int x; |
| 82 | int y; | 115 | int y; |
| 83 | int clip_right; | 116 | int clip_right; |
| @@ -116,6 +149,19 @@ void x_draw_xwidget_glyph_string (struct glyph_string *); | |||
| 116 | struct xwidget *lookup_xwidget (Lisp_Object spec); | 149 | struct xwidget *lookup_xwidget (Lisp_Object spec); |
| 117 | void xwidget_end_redisplay (struct window *, struct glyph_matrix *); | 150 | void xwidget_end_redisplay (struct window *, struct glyph_matrix *); |
| 118 | void kill_buffer_xwidgets (Lisp_Object); | 151 | void kill_buffer_xwidgets (Lisp_Object); |
| 152 | /* Defined in 'xwidget.c'. */ | ||
| 153 | void store_xwidget_event_string (struct xwidget *xw, | ||
| 154 | const char *eventname, | ||
| 155 | const char *eventstr); | ||
| 156 | |||
| 157 | void store_xwidget_download_callback_event (struct xwidget *xw, | ||
| 158 | const char *url, | ||
| 159 | const char *mimetype, | ||
| 160 | const char *filename); | ||
| 161 | |||
| 162 | void store_xwidget_js_callback_event (struct xwidget *xw, | ||
| 163 | Lisp_Object proc, | ||
| 164 | Lisp_Object argument); | ||
| 119 | #else | 165 | #else |
| 120 | INLINE_HEADER_BEGIN | 166 | INLINE_HEADER_BEGIN |
| 121 | INLINE void syms_of_xwidget (void) {} | 167 | INLINE void syms_of_xwidget (void) {} |