This source file includes following definitions.
- pgtk_device_added_or_removal_cb
- pgtk_seat_added_cb
- pgtk_seat_removed_cb
- pgtk_enumerate_devices
- pgtk_free_devices
- pgtk_regenerate_devices
- pgtk_toolkit_position
- pgtk_get_device_for_event
- flip_cr_context
- evq_enqueue
- evq_flush
- mark_pgtkterm
- get_keysym_name
- frame_set_mouse_pixel_position
- pgtk_raise_frame
- pgtk_lower_frame
- pgtk_frame_raise_lower
- pgtk_free_frame_resources
- pgtk_destroy_window
- pgtk_calc_absolute_position
- pgtk_set_offset
- pgtk_set_window_size
- pgtk_iconify_frame
- pgtk_make_frame_visible_wait_for_map_event_cb
- pgtk_make_frame_visible_wait_for_map_event_timeout
- pgtk_wait_for_map_event
- pgtk_make_frame_visible
- pgtk_make_frame_invisible
- pgtk_make_frame_visible_invisible
- pgtk_new_font
- pgtk_display_pixel_height
- pgtk_display_pixel_width
- pgtk_set_parent_frame
- pgtk_set_no_focus_on_map
- pgtk_set_no_accept_focus
- pgtk_set_z_group
- pgtk_initialize_display_info
- pgtk_set_cursor_gc
- pgtk_set_mouse_face_gc
- pgtk_set_mode_line_face_gc
- pgtk_set_glyph_string_gc
- pgtk_set_glyph_string_clipping
- pgtk_set_glyph_string_clipping_exactly
- pgtk_compute_glyph_string_overhangs
- pgtk_clear_glyph_string_rect
- fill_background_by_face
- fill_background
- pgtk_draw_glyph_string_background
- pgtk_draw_rectangle
- pgtk_draw_glyph_string_foreground
- pgtk_draw_composite_glyph_string_foreground
- pgtk_draw_glyphless_glyph_string_foreground
- pgtk_compute_lighter_color
- pgtk_fill_trapezoid_for_relief
- pgtk_erase_corners_for_relief
- pgtk_setup_relief_color
- pgtk_setup_relief_colors
- pgtk_set_clip_rectangles
- pgtk_draw_relief_rect
- pgtk_draw_box_rect
- pgtk_draw_glyph_string_box
- pgtk_draw_horizontal_wave
- pgtk_draw_underwave
- pgtk_draw_image_relief
- pgtk_draw_glyph_string_bg_rect
- pgtk_cr_draw_image
- pgtk_draw_image_foreground
- pgtk_draw_image_glyph_string
- pgtk_draw_stretch_glyph_string
- pgtk_draw_glyph_string
- pgtk_define_frame_cursor
- pgtk_after_update_window_line
- pgtk_clear_frame_area
- pgtk_draw_hollow_cursor
- pgtk_draw_bar_cursor
- pgtk_draw_window_cursor
- pgtk_copy_bits
- pgtk_scroll_run
- pgtk_bitmap_icon
- pgtk_text_icon
- pgtk_update_begin
- pgtk_draw_vertical_window_border
- pgtk_draw_window_divider
- pgtk_update_end
- pgtk_frame_up_to_date
- pgtk_mouse_position
- pgtk_define_fringe_bitmap
- pgtk_destroy_fringe_bitmap
- pgtk_clip_to_row
- pgtk_draw_fringe_bitmap
- hourglass_cb
- pgtk_show_hourglass
- pgtk_hide_hourglass
- pgtk_flush_display
- pgtk_clear_frame
- recover_from_visible_bell
- pgtk_flash
- pgtk_ring_bell
- pgtk_read_socket
- pgtk_send_scroll_bar_event
- xg_scroll_callback
- xg_end_scroll_callback
- pgtk_create_toolkit_scroll_bar
- pgtk_create_horizontal_toolkit_scroll_bar
- pgtk_set_toolkit_scroll_bar_thumb
- pgtk_set_toolkit_horizontal_scroll_bar_thumb
- pgtk_scroll_bar_create
- pgtk_scroll_bar_remove
- pgtk_set_vertical_scroll_bar
- pgtk_set_horizontal_scroll_bar
- pgtk_condemn_scroll_bars
- pgtk_redeem_scroll_bar
- pgtk_judge_scroll_bars
- set_fullscreen_state
- pgtk_fullscreen_hook
- pgtk_delete_terminal
- pgtk_query_frame_background_color
- pgtk_free_pixmap
- pgtk_focus_frame
- set_opacity_recursively
- pgtk_set_frame_alpha
- frame_highlight
- frame_unhighlight
- pgtk_frame_rehighlight
- pgtk_frame_rehighlight_hook
- pgtk_toggle_invisible_pointer
- pgtk_new_focus_frame
- pgtk_buffer_flipping_unblocked_hook
- pgtk_create_terminal
- pgtk_window_is_of_frame_recursive
- pgtk_window_is_of_frame
- pgtk_any_window_to_frame
- pgtk_handle_event
- pgtk_fill_rectangle
- pgtk_clear_under_internal_border
- pgtk_handle_draw
- size_allocate
- get_modifier_values
- pgtk_gtk_to_emacs_modifiers
- pgtk_emacs_to_gtk_modifiers
- pgtk_enqueue_string
- pgtk_enqueue_preedit
- key_press_event
- pgtk_display_info_for_display
- key_release_event
- configure_event
- map_event
- window_state_event
- delete_event
- pgtk_focus_changed
- enter_notify_event
- leave_notify_event
- focus_in_event
- focus_out_event
- note_mouse_movement
- motion_notify_event
- construct_mouse_click
- button_event
- scroll_event
- symbol_to_drag_action
- drag_action_to_symbol
- pgtk_update_drop_status
- pgtk_finish_drop
- drag_leave
- drag_motion
- drag_drop
- pgtk_monitors_changed_cb
- pgtk_set_event_handler
- my_log_handler
- same_x_server
- pgtk_find_selection_owner
- pgtk_selection_event
- pgtk_display_x_warning
- pgtk_term_init
- pgtk_delete_display
- pgtk_xlfd_to_fontname
- pgtk_defined_color
- pgtk_parse_color
- pgtk_query_colors
- pgtk_query_color
- pgtk_clear_area
- syms_of_pgtkterm
- pgtk_cr_update_surface_desired_size
- pgtk_begin_cr_clip
- pgtk_end_cr_clip
- pgtk_set_cr_source_with_gc_foreground
- pgtk_set_cr_source_with_gc_background
- pgtk_set_cr_source_with_color
- pgtk_cr_draw_frame
- pgtk_cr_accumulate_data
- pgtk_cr_destroy_frame_context
- pgtk_cr_destroy
- pgtk_cr_export_frames
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 #include <config.h>
24
25 #include <cairo.h>
26 #include <fcntl.h>
27 #include <math.h>
28 #include <pthread.h>
29 #include <sys/types.h>
30 #include <time.h>
31 #include <signal.h>
32 #include <unistd.h>
33 #include <errno.h>
34
35 #include <c-ctype.h>
36 #include <c-strcase.h>
37 #include <ftoastr.h>
38
39 #include <dlfcn.h>
40
41 #include "lisp.h"
42 #include "blockinput.h"
43 #include "frame.h"
44 #include "sysselect.h"
45 #include "gtkutil.h"
46 #include "systime.h"
47 #include "character.h"
48 #include "xwidget.h"
49 #include "fontset.h"
50 #include "composite.h"
51 #include "ccl.h"
52
53 #include "termhooks.h"
54 #include "termopts.h"
55 #include "termchar.h"
56 #include "emacs-icon.h"
57 #include "menu.h"
58 #include "window.h"
59 #include "keyboard.h"
60 #include "atimer.h"
61 #include "buffer.h"
62 #include "font.h"
63 #include "xsettings.h"
64 #include "emacsgtkfixed.h"
65
66 #ifdef GDK_WINDOWING_WAYLAND
67 #include <gdk/gdkwayland.h>
68 #endif
69
70 #define FRAME_CR_CONTEXT(f) ((f)->output_data.pgtk->cr_context)
71 #define FRAME_CR_ACTIVE_CONTEXT(f) ((f)->output_data.pgtk->cr_active)
72 #define FRAME_CR_SURFACE(f) (cairo_get_target (FRAME_CR_CONTEXT (f)))
73
74
75
76
77 static bool any_help_event_p;
78
79
80 struct pgtk_display_info *x_display_list;
81
82 struct event_queue_t
83 {
84 union buffered_input_event *q;
85 int nr, cap;
86 };
87
88
89 static struct event_queue_t event_q;
90
91
92
93
94 static Time ignore_next_mouse_click_timeout;
95
96
97 static Lisp_Object xg_default_icon_file;
98
99
100 static GdkDragContext *current_drop_context;
101
102
103
104 static bool current_drop_context_drop;
105
106
107 static guint32 current_drop_time;
108
109 static void pgtk_delete_display (struct pgtk_display_info *);
110 static void pgtk_clear_frame_area (struct frame *, int, int, int, int);
111 static void pgtk_fill_rectangle (struct frame *, unsigned long, int, int,
112 int, int, bool);
113 static void pgtk_clip_to_row (struct window *, struct glyph_row *,
114 enum glyph_row_area, cairo_t *);
115 static struct frame *pgtk_any_window_to_frame (GdkWindow *);
116 static void pgtk_regenerate_devices (struct pgtk_display_info *);
117
118 static void
119 pgtk_device_added_or_removal_cb (GdkSeat *seat, GdkDevice *device,
120 gpointer user_data)
121 {
122 pgtk_regenerate_devices (user_data);
123 }
124
125 static void
126 pgtk_seat_added_cb (GdkDisplay *dpy, GdkSeat *seat,
127 gpointer user_data)
128 {
129 pgtk_regenerate_devices (user_data);
130
131 g_signal_connect (G_OBJECT (seat), "device-added",
132 G_CALLBACK (pgtk_device_added_or_removal_cb),
133 user_data);
134 g_signal_connect (G_OBJECT (seat), "device-removed",
135 G_CALLBACK (pgtk_device_added_or_removal_cb),
136 user_data);
137 }
138
139 static void
140 pgtk_seat_removed_cb (GdkDisplay *dpy, GdkSeat *seat,
141 gpointer user_data)
142 {
143 pgtk_regenerate_devices (user_data);
144
145 g_signal_handlers_disconnect_by_func (G_OBJECT (seat),
146 G_CALLBACK (pgtk_device_added_or_removal_cb),
147 user_data);
148 }
149
150 static void
151 pgtk_enumerate_devices (struct pgtk_display_info *dpyinfo,
152 bool initial_p)
153 {
154 struct pgtk_device_t *rec;
155 GList *all_seats, *devices_on_seat, *tem, *t1;
156 GdkSeat *seat;
157 char printbuf[1026];
158
159
160 block_input ();
161 all_seats = gdk_display_list_seats (dpyinfo->gdpy);
162
163 for (tem = all_seats; tem; tem = tem->next)
164 {
165 seat = GDK_SEAT (tem->data);
166
167 if (initial_p)
168 {
169 g_signal_connect (G_OBJECT (seat), "device-added",
170 G_CALLBACK (pgtk_device_added_or_removal_cb),
171 dpyinfo);
172 g_signal_connect (G_OBJECT (seat), "device-removed",
173 G_CALLBACK (pgtk_device_added_or_removal_cb),
174 dpyinfo);
175 }
176
177
178 devices_on_seat = gdk_seat_get_slaves (seat,
179 GDK_SEAT_CAPABILITY_ALL);
180
181 for (t1 = devices_on_seat; t1; t1 = t1->next)
182 {
183 rec = xmalloc (sizeof *rec);
184 rec->seat = g_object_ref (seat);
185 rec->device = GDK_DEVICE (t1->data);
186
187 snprintf (printbuf, 1026, "%u:%s",
188 gdk_device_get_source (rec->device),
189 gdk_device_get_name (rec->device));
190
191 rec->name = build_string (printbuf);
192 rec->next = dpyinfo->devices;
193 dpyinfo->devices = rec;
194 }
195
196 g_list_free (devices_on_seat);
197 }
198
199 g_list_free (all_seats);
200 unblock_input ();
201 }
202
203 static void
204 pgtk_free_devices (struct pgtk_display_info *dpyinfo)
205 {
206 struct pgtk_device_t *last, *tem;
207
208 tem = dpyinfo->devices;
209 while (tem)
210 {
211 last = tem;
212 tem = tem->next;
213
214 g_object_unref (last->seat);
215 xfree (last);
216 }
217
218 dpyinfo->devices = NULL;
219 }
220
221 static void
222 pgtk_regenerate_devices (struct pgtk_display_info *dpyinfo)
223 {
224 pgtk_free_devices (dpyinfo);
225 pgtk_enumerate_devices (dpyinfo, false);
226 }
227
228 static void
229 pgtk_toolkit_position (struct frame *f, int x, int y,
230 bool *menu_bar_p, bool *tool_bar_p)
231 {
232 GdkRectangle test_rect;
233 int scale;
234
235 y += (FRAME_MENUBAR_HEIGHT (f)
236 + FRAME_TOOLBAR_TOP_HEIGHT (f));
237 x += FRAME_TOOLBAR_LEFT_WIDTH (f);
238
239 if (FRAME_EXTERNAL_MENU_BAR (f))
240 *menu_bar_p = (x >= 0 && x < FRAME_PIXEL_WIDTH (f)
241 && y >= 0 && y < FRAME_MENUBAR_HEIGHT (f));
242
243 if (FRAME_X_OUTPUT (f)->toolbar_widget)
244 {
245 scale = xg_get_scale (f);
246 test_rect.x = x / scale;
247 test_rect.y = y / scale;
248 test_rect.width = 1;
249 test_rect.height = 1;
250
251 *tool_bar_p = gtk_widget_intersect (FRAME_X_OUTPUT (f)->toolbar_widget,
252 &test_rect, NULL);
253 }
254 }
255
256 static Lisp_Object
257 pgtk_get_device_for_event (struct pgtk_display_info *dpyinfo,
258 GdkEvent *event)
259 {
260 struct pgtk_device_t *tem;
261 GdkDevice *device;
262
263 device = gdk_event_get_source_device (event);
264
265 if (!device)
266 return Qt;
267
268 for (tem = dpyinfo->devices; tem; tem = tem->next)
269 {
270 if (tem->device == device)
271 return tem->name;
272 }
273
274 return Qt;
275 }
276
277
278
279
280
281
282 static void
283 flip_cr_context (struct frame *f)
284 {
285 cairo_t *cr = FRAME_CR_ACTIVE_CONTEXT (f);
286
287 block_input ();
288 if (cr != FRAME_CR_CONTEXT (f))
289 {
290 cairo_destroy (cr);
291
292 FRAME_CR_ACTIVE_CONTEXT (f)
293 = cairo_reference (FRAME_CR_CONTEXT (f));
294 }
295 unblock_input ();
296 }
297
298
299 static void
300 evq_enqueue (union buffered_input_event *ev)
301 {
302 struct event_queue_t *evq = &event_q;
303 struct frame *frame;
304 struct pgtk_display_info *dpyinfo;
305
306 if (evq->cap == 0)
307 {
308 evq->cap = 4;
309 evq->q = xmalloc (sizeof *evq->q * evq->cap);
310 }
311
312 if (evq->nr >= evq->cap)
313 {
314 evq->cap += evq->cap / 2;
315 evq->q = xrealloc (evq->q, sizeof *evq->q * evq->cap);
316 }
317
318 evq->q[evq->nr++] = *ev;
319
320 if (ev->ie.kind != SELECTION_REQUEST_EVENT
321 && ev->ie.kind != SELECTION_CLEAR_EVENT)
322 {
323 frame = NULL;
324
325 if (WINDOWP (ev->ie.frame_or_window))
326 frame = WINDOW_XFRAME (XWINDOW (ev->ie.frame_or_window));
327
328 if (FRAMEP (ev->ie.frame_or_window))
329 frame = XFRAME (ev->ie.frame_or_window);
330
331 if (frame)
332 {
333 dpyinfo = FRAME_DISPLAY_INFO (frame);
334
335 if (dpyinfo->last_user_time < ev->ie.timestamp)
336 dpyinfo->last_user_time = ev->ie.timestamp;
337 }
338 }
339
340 raise (SIGIO);
341 }
342
343 static int
344 evq_flush (struct input_event *hold_quit)
345 {
346 struct event_queue_t *evq = &event_q;
347 int n = 0;
348
349 while (evq->nr > 0)
350 {
351
352
353
354
355 union buffered_input_event ev = evq->q[0];
356 int i;
357 for (i = 1; i < evq->nr; i++)
358 evq->q[i - 1] = evq->q[i];
359 evq->nr--;
360
361 kbd_buffer_store_buffered_event (&ev, hold_quit);
362 n++;
363 }
364
365 return n;
366 }
367
368 void
369 mark_pgtkterm (void)
370 {
371 struct pgtk_display_info *dpyinfo;
372 struct pgtk_device_t *device;
373 struct event_queue_t *evq = &event_q;
374 int i, n = evq->nr;
375
376 for (i = 0; i < n; i++)
377 {
378 union buffered_input_event *ev = &evq->q[i];
379
380
381
382 if (ev->ie.kind == SELECTION_REQUEST_EVENT
383 || ev->ie.kind == SELECTION_CLEAR_EVENT)
384 continue;
385
386 mark_object (ev->ie.x);
387 mark_object (ev->ie.y);
388 mark_object (ev->ie.frame_or_window);
389 mark_object (ev->ie.arg);
390 mark_object (ev->ie.device);
391 }
392
393 for (dpyinfo = x_display_list; dpyinfo;
394 dpyinfo = dpyinfo->next)
395 {
396 for (device = dpyinfo->devices; device;
397 device = device->next)
398 mark_object (device->name);
399 }
400 }
401
402 char *
403 get_keysym_name (int keysym)
404 {
405 return gdk_keyval_name (keysym);
406 }
407
408 void
409 frame_set_mouse_pixel_position (struct frame *f, int pix_x, int pix_y)
410
411
412
413 {
414 }
415
416
417
418 static void
419 pgtk_raise_frame (struct frame *f)
420 {
421
422
423
424 block_input ();
425 if (FRAME_VISIBLE_P (f))
426 gdk_window_raise (gtk_widget_get_window (FRAME_WIDGET (f)));
427 unblock_input ();
428 }
429
430
431
432 static void
433 pgtk_lower_frame (struct frame *f)
434 {
435 if (FRAME_VISIBLE_P (f))
436 {
437 block_input ();
438 gdk_window_lower (gtk_widget_get_window (FRAME_WIDGET (f)));
439 unblock_input ();
440 }
441 }
442
443 static void
444 pgtk_frame_raise_lower (struct frame *f, bool raise_flag)
445 {
446 if (raise_flag)
447 pgtk_raise_frame (f);
448 else
449 pgtk_lower_frame (f);
450 }
451
452
453
454 void
455 pgtk_free_frame_resources (struct frame *f)
456 {
457 struct pgtk_display_info *dpyinfo;
458 Mouse_HLInfo *hlinfo;
459
460 check_window_system (f);
461 dpyinfo = FRAME_DISPLAY_INFO (f);
462 hlinfo = MOUSE_HL_INFO (f);
463
464 block_input ();
465
466 #ifdef HAVE_XWIDGETS
467 kill_frame_xwidget_views (f);
468 #endif
469 free_frame_faces (f);
470
471 if (FRAME_X_OUTPUT (f)->scale_factor_atimer != NULL)
472 {
473 cancel_atimer (FRAME_X_OUTPUT (f)->scale_factor_atimer);
474 FRAME_X_OUTPUT (f)->scale_factor_atimer = NULL;
475 }
476
477 #define CLEAR_IF_EQ(FIELD) \
478 do { if (f == dpyinfo->FIELD) dpyinfo->FIELD = 0; } while (false)
479
480 CLEAR_IF_EQ (x_focus_frame);
481 CLEAR_IF_EQ (highlight_frame);
482 CLEAR_IF_EQ (x_focus_event_frame);
483 CLEAR_IF_EQ (last_mouse_frame);
484 CLEAR_IF_EQ (last_mouse_motion_frame);
485 CLEAR_IF_EQ (last_mouse_glyph_frame);
486 CLEAR_IF_EQ (im.focused_frame);
487
488 #undef CLEAR_IF_EQ
489
490 if (f == hlinfo->mouse_face_mouse_frame)
491 reset_mouse_highlight (hlinfo);
492
493 g_clear_object (&FRAME_X_OUTPUT (f)->text_cursor);
494 g_clear_object (&FRAME_X_OUTPUT (f)->nontext_cursor);
495 g_clear_object (&FRAME_X_OUTPUT (f)->modeline_cursor);
496 g_clear_object (&FRAME_X_OUTPUT (f)->hand_cursor);
497 g_clear_object (&FRAME_X_OUTPUT (f)->hourglass_cursor);
498 g_clear_object (&FRAME_X_OUTPUT (f)->horizontal_drag_cursor);
499 g_clear_object (&FRAME_X_OUTPUT (f)->vertical_drag_cursor);
500 g_clear_object (&FRAME_X_OUTPUT (f)->left_edge_cursor);
501 g_clear_object (&FRAME_X_OUTPUT (f)->right_edge_cursor);
502 g_clear_object (&FRAME_X_OUTPUT (f)->top_edge_cursor);
503 g_clear_object (&FRAME_X_OUTPUT (f)->bottom_edge_cursor);
504 g_clear_object (&FRAME_X_OUTPUT (f)->top_left_corner_cursor);
505 g_clear_object (&FRAME_X_OUTPUT (f)->top_right_corner_cursor);
506 g_clear_object (&FRAME_X_OUTPUT (f)->bottom_right_corner_cursor);
507 g_clear_object (&FRAME_X_OUTPUT (f)->bottom_left_corner_cursor);
508
509
510 if (FRAME_X_OUTPUT (f)->border_color_css_provider != NULL)
511 {
512 GtkStyleContext *ctxt = gtk_widget_get_style_context (FRAME_WIDGET (f));
513 GtkCssProvider *old = FRAME_X_OUTPUT (f)->border_color_css_provider;
514 gtk_style_context_remove_provider (ctxt, GTK_STYLE_PROVIDER (old));
515 g_object_unref (old);
516 FRAME_X_OUTPUT (f)->border_color_css_provider = NULL;
517 }
518
519 if (FRAME_X_OUTPUT (f)->scrollbar_foreground_css_provider != NULL)
520 {
521 GtkCssProvider *old
522 = FRAME_X_OUTPUT (f)->scrollbar_foreground_css_provider;
523 g_object_unref (old);
524 FRAME_X_OUTPUT (f)->scrollbar_foreground_css_provider = NULL;
525 }
526
527 if (FRAME_X_OUTPUT (f)->scrollbar_background_css_provider != NULL)
528 {
529 GtkCssProvider *old
530 = FRAME_X_OUTPUT (f)->scrollbar_background_css_provider;
531 g_object_unref (old);
532 FRAME_X_OUTPUT (f)->scrollbar_background_css_provider = NULL;
533 }
534
535 gtk_widget_destroy (FRAME_WIDGET (f));
536
537 if (FRAME_X_OUTPUT (f)->cr_surface_visible_bell != NULL)
538 {
539 cairo_surface_destroy (FRAME_X_OUTPUT (f)->cr_surface_visible_bell);
540 FRAME_X_OUTPUT (f)->cr_surface_visible_bell = NULL;
541 }
542
543 if (FRAME_X_OUTPUT (f)->atimer_visible_bell != NULL)
544 {
545 cancel_atimer (FRAME_X_OUTPUT (f)->atimer_visible_bell);
546 FRAME_X_OUTPUT (f)->atimer_visible_bell = NULL;
547 }
548
549 xfree (f->output_data.pgtk);
550 f->output_data.pgtk = NULL;
551
552 unblock_input ();
553 }
554
555 void
556 pgtk_destroy_window (struct frame *f)
557
558
559
560 {
561 struct pgtk_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
562
563 check_window_system (f);
564 if (dpyinfo->gdpy != NULL)
565 pgtk_free_frame_resources (f);
566
567 dpyinfo->reference_count--;
568 }
569
570
571
572
573 static void
574 pgtk_calc_absolute_position (struct frame *f)
575 {
576 int flags = f->size_hint_flags;
577 struct frame *p = FRAME_PARENT_FRAME (f);
578
579
580
581 if (! ((flags & XNegative) || (flags & YNegative)))
582 return;
583
584
585
586 if ((flags & XNegative) && (f->left_pos <= 0))
587 {
588 int width = FRAME_PIXEL_WIDTH (f);
589
590
591
592 if (f->output_data.pgtk->has_been_visible && !p)
593 {
594 Lisp_Object frame;
595 Lisp_Object edges = Qnil;
596
597 XSETFRAME (frame, f);
598 edges = Fpgtk_frame_edges (frame, Qouter_edges);
599 if (!NILP (edges))
600 width = (XFIXNUM (Fnth (make_fixnum (2), edges))
601 - XFIXNUM (Fnth (make_fixnum (0), edges)));
602 }
603
604 if (p)
605 f->left_pos = (FRAME_PIXEL_WIDTH (p) - width - 2 * f->border_width
606 + f->left_pos);
607 else
608 f->left_pos = (pgtk_display_pixel_width (FRAME_DISPLAY_INFO (f))
609 - width + f->left_pos);
610
611 }
612
613 if ((flags & YNegative) && (f->top_pos <= 0))
614 {
615 int height = FRAME_PIXEL_HEIGHT (f);
616
617 if (f->output_data.pgtk->has_been_visible && !p)
618 {
619 Lisp_Object frame;
620 Lisp_Object edges = Qnil;
621
622 XSETFRAME (frame, f);
623 if (NILP (edges))
624 edges = Fpgtk_frame_edges (frame, Qouter_edges);
625 if (!NILP (edges))
626 height = (XFIXNUM (Fnth (make_fixnum (3), edges))
627 - XFIXNUM (Fnth (make_fixnum (1), edges)));
628 }
629
630 if (p)
631 f->top_pos = (FRAME_PIXEL_HEIGHT (p) - height - 2 * f->border_width
632 + f->top_pos);
633 else
634 f->top_pos = (pgtk_display_pixel_height (FRAME_DISPLAY_INFO (f))
635 - height + f->top_pos);
636 }
637
638
639
640
641 f->size_hint_flags &= ~ (XNegative | YNegative);
642 }
643
644
645
646
647
648
649
650 static void
651 pgtk_set_offset (struct frame *f, int xoff, int yoff, int change_gravity)
652 {
653 if (change_gravity > 0)
654 {
655 f->top_pos = yoff;
656 f->left_pos = xoff;
657 f->size_hint_flags &= ~ (XNegative | YNegative);
658 if (xoff < 0)
659 f->size_hint_flags |= XNegative;
660 if (yoff < 0)
661 f->size_hint_flags |= YNegative;
662 f->win_gravity = NorthWestGravity;
663 }
664
665 pgtk_calc_absolute_position (f);
666
667 block_input ();
668 xg_wm_set_size_hint (f, 0, false);
669
670 if (change_gravity != 0)
671 {
672 if (FRAME_GTK_OUTER_WIDGET (f))
673 gtk_window_move (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
674 f->left_pos, f->top_pos);
675 else
676 {
677 GtkWidget *fixed = FRAME_GTK_WIDGET (f);
678 GtkWidget *parent = gtk_widget_get_parent (fixed);
679 gtk_fixed_move (GTK_FIXED (parent), fixed,
680 f->left_pos, f->top_pos);
681 }
682 }
683 unblock_input ();
684 return;
685 }
686
687 static void
688 pgtk_set_window_size (struct frame *f, bool change_gravity,
689 int width, int height)
690
691
692
693
694
695 {
696 int pixelwidth, pixelheight;
697
698 block_input ();
699
700 gtk_widget_get_size_request (FRAME_GTK_WIDGET (f), &pixelwidth,
701 &pixelheight);
702
703 pixelwidth = width;
704 pixelheight = height;
705
706 for (GtkWidget * w = FRAME_GTK_WIDGET (f); w != NULL;
707 w = gtk_widget_get_parent (w))
708 {
709 gint wd, hi;
710 gtk_widget_get_size_request (w, &wd, &hi);
711 }
712
713 f->output_data.pgtk->preferred_width = pixelwidth;
714 f->output_data.pgtk->preferred_height = pixelheight;
715 xg_wm_set_size_hint (f, 0, 0);
716 xg_frame_set_char_size (f, pixelwidth, pixelheight);
717 gtk_widget_queue_resize (FRAME_WIDGET (f));
718
719 unblock_input ();
720 }
721
722 void
723 pgtk_iconify_frame (struct frame *f)
724 {
725 GtkWindow *window;
726
727
728
729 if (FRAME_DISPLAY_INFO (f)->highlight_frame == f)
730 FRAME_DISPLAY_INFO (f)->highlight_frame = NULL;
731
732
733
734 if (FRAME_ICONIFIED_P (f))
735 return;
736
737
738
739
740 if (FRAME_GTK_OUTER_WIDGET (f))
741 {
742 if (!FRAME_VISIBLE_P (f))
743 gtk_widget_show_all (FRAME_GTK_OUTER_WIDGET (f));
744
745 window = GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f));
746
747 gtk_window_iconify (window);
748
749
750
751
752
753
754
755
756
757
758
759 }
760 }
761
762 static gboolean
763 pgtk_make_frame_visible_wait_for_map_event_cb (GtkWidget *widget,
764 GdkEventAny *event,
765 gpointer user_data)
766 {
767 int *foundptr = user_data;
768 *foundptr = 1;
769 return FALSE;
770 }
771
772 static gboolean
773 pgtk_make_frame_visible_wait_for_map_event_timeout (gpointer user_data)
774 {
775 int *timedoutptr = user_data;
776 *timedoutptr = 1;
777 return FALSE;
778 }
779
780 static void
781 pgtk_wait_for_map_event (struct frame *f, bool multiple_times)
782 {
783 if (FLOATP (Vpgtk_wait_for_event_timeout))
784 {
785 guint msec
786 = (guint) (XFLOAT_DATA (Vpgtk_wait_for_event_timeout) * 1000);
787 int found = 0;
788 int timed_out = 0;
789 gulong id
790 = g_signal_connect (FRAME_WIDGET (f), "map-event",
791 G_CALLBACK
792 (pgtk_make_frame_visible_wait_for_map_event_cb),
793 &found);
794 guint src
795 = g_timeout_add (msec,
796 pgtk_make_frame_visible_wait_for_map_event_timeout,
797 &timed_out);
798
799 if (!multiple_times)
800 {
801 while (!found && !timed_out)
802 gtk_main_iteration ();
803 }
804 else
805 {
806 while (!timed_out)
807 gtk_main_iteration ();
808 }
809
810 g_signal_handler_disconnect (FRAME_WIDGET (f), id);
811
812 if (!timed_out)
813 g_source_remove (src);
814 }
815 }
816
817 void
818 pgtk_make_frame_visible (struct frame *f)
819 {
820 GtkWidget *win = FRAME_GTK_OUTER_WIDGET (f);
821
822 if (!FRAME_VISIBLE_P (f))
823 {
824 gtk_widget_show (FRAME_WIDGET (f));
825 if (win)
826 gtk_window_deiconify (GTK_WINDOW (win));
827
828 pgtk_wait_for_map_event (f, false);
829 }
830 }
831
832
833 void
834 pgtk_make_frame_invisible (struct frame *f)
835 {
836 gtk_widget_hide (FRAME_WIDGET (f));
837
838
839
840 pgtk_wait_for_map_event (f, true);
841
842 SET_FRAME_VISIBLE (f, 0);
843 SET_FRAME_ICONIFIED (f, false);
844 }
845
846 static void
847 pgtk_make_frame_visible_invisible (struct frame *f, bool visible)
848 {
849 if (visible)
850 pgtk_make_frame_visible (f);
851 else
852 pgtk_make_frame_invisible (f);
853 }
854
855 static Lisp_Object
856 pgtk_new_font (struct frame *f, Lisp_Object font_object, int fontset)
857 {
858 struct font *font = XFONT_OBJECT (font_object);
859 int font_ascent, font_descent;
860
861 if (fontset < 0)
862 fontset = fontset_from_font (font_object);
863 FRAME_FONTSET (f) = fontset;
864
865 if (FRAME_FONT (f) == font)
866 {
867
868
869 return font_object;
870 }
871
872 FRAME_FONT (f) = font;
873
874 FRAME_BASELINE_OFFSET (f) = font->baseline_offset;
875 FRAME_COLUMN_WIDTH (f) = font->average_width;
876 get_font_ascent_descent (font, &font_ascent, &font_descent);
877 FRAME_LINE_HEIGHT (f) = font_ascent + font_descent;
878
879
880 FRAME_TAB_BAR_HEIGHT (f) = FRAME_TAB_BAR_LINES (f) * FRAME_LINE_HEIGHT (f);
881
882
883 if (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) > 0)
884 {
885 int wid = FRAME_COLUMN_WIDTH (f);
886 FRAME_CONFIG_SCROLL_BAR_COLS (f)
887 = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) + wid - 1) / wid;
888 }
889 else
890 {
891 int wid = FRAME_COLUMN_WIDTH (f);
892 FRAME_CONFIG_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
893 }
894
895
896 if (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) > 0)
897 {
898 int height = FRAME_LINE_HEIGHT (f);
899 FRAME_CONFIG_SCROLL_BAR_LINES (f)
900 = (FRAME_CONFIG_SCROLL_BAR_HEIGHT (f) + height - 1) / height;
901 }
902 else
903 {
904 int height = FRAME_LINE_HEIGHT (f);
905 FRAME_CONFIG_SCROLL_BAR_LINES (f) = (14 + height - 1) / height;
906 }
907
908
909 if (FRAME_GTK_WIDGET (f) != NULL)
910 adjust_frame_size (f, FRAME_COLS (f) * FRAME_COLUMN_WIDTH (f),
911 FRAME_LINES (f) * FRAME_LINE_HEIGHT (f), 3,
912 false, Qfont);
913
914 return font_object;
915 }
916
917 int
918 pgtk_display_pixel_height (struct pgtk_display_info *dpyinfo)
919 {
920 GdkDisplay *gdpy = dpyinfo->gdpy;
921 GdkScreen *gscr = gdk_display_get_default_screen (gdpy);
922
923 return gdk_screen_get_height (gscr);
924 }
925
926 int
927 pgtk_display_pixel_width (struct pgtk_display_info *dpyinfo)
928 {
929 GdkDisplay *gdpy = dpyinfo->gdpy;
930 GdkScreen *gscr = gdk_display_get_default_screen (gdpy);
931
932 return gdk_screen_get_width (gscr);
933 }
934
935 void
936 pgtk_set_parent_frame (struct frame *f, Lisp_Object new_value,
937 Lisp_Object old_value)
938 {
939 struct frame *p = NULL;
940
941 if (!NILP (new_value)
942 && (!FRAMEP (new_value)
943 || !FRAME_LIVE_P (p = XFRAME (new_value))
944 || !FRAME_PGTK_P (p)))
945 {
946 store_frame_param (f, Qparent_frame, old_value);
947 error ("Invalid specification of `parent-frame'");
948 }
949
950 if (p != FRAME_PARENT_FRAME (f))
951 {
952 block_input ();
953
954 if (p != NULL)
955 {
956 if (FRAME_DISPLAY_INFO (f) != FRAME_DISPLAY_INFO (p))
957 error ("Cross display reparent.");
958 }
959
960 GtkWidget *fixed = FRAME_GTK_WIDGET (f);
961
962 GtkAllocation alloc;
963 gtk_widget_get_allocation (fixed, &alloc);
964 g_object_ref (fixed);
965
966
967 GtkCssProvider *provider = FRAME_X_OUTPUT (f)->border_color_css_provider;
968 FRAME_X_OUTPUT (f)->border_color_css_provider = NULL;
969 {
970 GtkStyleContext *ctxt = gtk_widget_get_style_context (FRAME_WIDGET (f));
971 if (provider != NULL)
972 gtk_style_context_remove_provider (ctxt, GTK_STYLE_PROVIDER (provider));
973 }
974
975 {
976 GtkWidget *whbox_of_f = gtk_widget_get_parent (fixed);
977
978
979 gtk_container_remove (GTK_CONTAINER (whbox_of_f), fixed);
980
981 if (FRAME_GTK_OUTER_WIDGET (f))
982 {
983 gtk_widget_destroy (FRAME_GTK_OUTER_WIDGET (f));
984 FRAME_GTK_OUTER_WIDGET (f) = NULL;
985 FRAME_OUTPUT_DATA (f)->vbox_widget = NULL;
986 FRAME_OUTPUT_DATA (f)->hbox_widget = NULL;
987 FRAME_OUTPUT_DATA (f)->menubar_widget = NULL;
988 FRAME_OUTPUT_DATA (f)->toolbar_widget = NULL;
989 FRAME_OUTPUT_DATA (f)->ttip_widget = NULL;
990 FRAME_OUTPUT_DATA (f)->ttip_lbl = NULL;
991 FRAME_OUTPUT_DATA (f)->ttip_window = NULL;
992 }
993 }
994
995 if (p == NULL)
996 {
997 xg_create_frame_outer_widgets (f);
998 pgtk_set_event_handler (f);
999 gtk_box_pack_start (GTK_BOX (f->output_data.pgtk->hbox_widget),
1000 fixed, TRUE, TRUE, 0);
1001 f->output_data.pgtk->preferred_width = alloc.width;
1002 f->output_data.pgtk->preferred_height = alloc.height;
1003 xg_wm_set_size_hint (f, 0, 0);
1004 xg_frame_set_char_size (f, FRAME_PIXEL_TO_TEXT_WIDTH (f, alloc.width),
1005 FRAME_PIXEL_TO_TEXT_HEIGHT (f, alloc.height));
1006 gtk_widget_queue_resize (FRAME_WIDGET (f));
1007 gtk_widget_show_all (FRAME_GTK_OUTER_WIDGET (f));
1008 }
1009 else
1010 {
1011 GtkWidget *fixed_of_p = FRAME_GTK_WIDGET (p);
1012 gtk_fixed_put (GTK_FIXED (fixed_of_p), fixed, f->left_pos, f->top_pos);
1013 gtk_widget_set_size_request (fixed, alloc.width, alloc.height);
1014 gtk_widget_show_all (fixed);
1015 }
1016
1017
1018 GtkStyleContext *ctxt = gtk_widget_get_style_context (FRAME_WIDGET (f));
1019 GtkCssProvider *old = FRAME_X_OUTPUT (f)->border_color_css_provider;
1020 FRAME_X_OUTPUT (f)->border_color_css_provider = provider;
1021 if (provider != NULL)
1022 {
1023 gtk_style_context_add_provider (ctxt, GTK_STYLE_PROVIDER (provider),
1024 GTK_STYLE_PROVIDER_PRIORITY_USER);
1025 }
1026 if (old != NULL)
1027 {
1028 gtk_style_context_remove_provider (ctxt, GTK_STYLE_PROVIDER (old));
1029 g_object_unref(old);
1030 }
1031
1032 g_object_unref (fixed);
1033
1034 unblock_input ();
1035
1036 fset_parent_frame (f, new_value);
1037 }
1038 }
1039
1040
1041 void
1042 pgtk_set_no_focus_on_map (struct frame *f, Lisp_Object new_value,
1043 Lisp_Object old_value)
1044 {
1045 if (!EQ (new_value, old_value))
1046 {
1047 xg_set_no_focus_on_map (f, new_value);
1048 FRAME_NO_FOCUS_ON_MAP (f) = !NILP (new_value);
1049 }
1050 }
1051
1052 void
1053 pgtk_set_no_accept_focus (struct frame *f, Lisp_Object new_value,
1054 Lisp_Object old_value)
1055 {
1056 xg_set_no_accept_focus (f, new_value);
1057 FRAME_NO_ACCEPT_FOCUS (f) = !NILP (new_value);
1058 }
1059
1060 void
1061 pgtk_set_z_group (struct frame *f, Lisp_Object new_value, Lisp_Object old_value)
1062 {
1063 if (!FRAME_GTK_OUTER_WIDGET (f))
1064 return;
1065
1066 if (NILP (new_value))
1067 {
1068 gtk_window_set_keep_above (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
1069 FALSE);
1070 gtk_window_set_keep_below (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
1071 FALSE);
1072 FRAME_Z_GROUP (f) = z_group_none;
1073 }
1074 else if (EQ (new_value, Qabove))
1075 {
1076 gtk_window_set_keep_above (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
1077 TRUE);
1078 gtk_window_set_keep_below (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
1079 FALSE);
1080 FRAME_Z_GROUP (f) = z_group_above;
1081 }
1082 else if (EQ (new_value, Qabove_suspended))
1083 {
1084 gtk_window_set_keep_above (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
1085 FALSE);
1086 FRAME_Z_GROUP (f) = z_group_above_suspended;
1087 }
1088 else if (EQ (new_value, Qbelow))
1089 {
1090 gtk_window_set_keep_above (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
1091 FALSE);
1092 gtk_window_set_keep_below (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
1093 TRUE);
1094 FRAME_Z_GROUP (f) = z_group_below;
1095 }
1096 else
1097 error ("Invalid z-group specification");
1098 }
1099
1100 static void
1101 pgtk_initialize_display_info (struct pgtk_display_info *dpyinfo)
1102
1103
1104
1105 {
1106 dpyinfo->resx = 96;
1107 dpyinfo->resy = 96;
1108 dpyinfo->color_p = 1;
1109 dpyinfo->n_planes = 32;
1110 dpyinfo->root_window = 42;
1111 dpyinfo->highlight_frame = dpyinfo->x_focus_frame = NULL;
1112 dpyinfo->n_fonts = 0;
1113 dpyinfo->smallest_font_height = 1;
1114 dpyinfo->smallest_char_width = 1;
1115
1116 reset_mouse_highlight (&dpyinfo->mouse_highlight);
1117 }
1118
1119
1120
1121
1122 static void
1123 pgtk_set_cursor_gc (struct glyph_string *s)
1124 {
1125 if (s->font == FRAME_FONT (s->f)
1126 && s->face->background == FRAME_BACKGROUND_PIXEL (s->f)
1127 && s->face->foreground == FRAME_FOREGROUND_PIXEL (s->f) && !s->cmp)
1128 s->xgcv = FRAME_X_OUTPUT (s->f)->cursor_xgcv;
1129 else
1130 {
1131
1132 Emacs_GC xgcv;
1133
1134 xgcv.background = FRAME_X_OUTPUT (s->f)->cursor_color;
1135 xgcv.foreground = s->face->background;
1136
1137
1138 if (xgcv.foreground == xgcv.background)
1139 xgcv.foreground = s->face->foreground;
1140 if (xgcv.foreground == xgcv.background)
1141 xgcv.foreground = FRAME_X_OUTPUT (s->f)->cursor_foreground_color;
1142 if (xgcv.foreground == xgcv.background)
1143 xgcv.foreground = s->face->foreground;
1144
1145
1146 if (xgcv.background == s->face->background
1147 && xgcv.foreground == s->face->foreground)
1148 {
1149 xgcv.background = s->face->foreground;
1150 xgcv.foreground = s->face->background;
1151 }
1152
1153 s->xgcv = xgcv;
1154 }
1155 }
1156
1157
1158
1159
1160 static void
1161 pgtk_set_mouse_face_gc (struct glyph_string *s)
1162 {
1163 prepare_face_for_display (s->f, s->face);
1164
1165 if (s->font == s->face->font)
1166 {
1167 s->xgcv.foreground = s->face->foreground;
1168 s->xgcv.background = s->face->background;
1169 }
1170 else
1171 {
1172
1173
1174 Emacs_GC xgcv;
1175
1176 xgcv.background = s->face->background;
1177 xgcv.foreground = s->face->foreground;
1178
1179 s->xgcv = xgcv;
1180
1181 }
1182 }
1183
1184
1185
1186
1187
1188
1189 static void
1190 pgtk_set_mode_line_face_gc (struct glyph_string *s)
1191 {
1192 s->xgcv.foreground = s->face->foreground;
1193 s->xgcv.background = s->face->background;
1194 }
1195
1196
1197
1198
1199
1200
1201 static void
1202 pgtk_set_glyph_string_gc (struct glyph_string *s)
1203 {
1204 prepare_face_for_display (s->f, s->face);
1205
1206 if (s->hl == DRAW_NORMAL_TEXT)
1207 {
1208 s->xgcv.foreground = s->face->foreground;
1209 s->xgcv.background = s->face->background;
1210 s->stippled_p = s->face->stipple != 0;
1211 }
1212 else if (s->hl == DRAW_INVERSE_VIDEO)
1213 {
1214 pgtk_set_mode_line_face_gc (s);
1215 s->stippled_p = s->face->stipple != 0;
1216 }
1217 else if (s->hl == DRAW_CURSOR)
1218 {
1219 pgtk_set_cursor_gc (s);
1220 s->stippled_p = false;
1221 }
1222 else if (s->hl == DRAW_MOUSE_FACE)
1223 {
1224 pgtk_set_mouse_face_gc (s);
1225 s->stippled_p = s->face->stipple != 0;
1226 }
1227 else if (s->hl == DRAW_IMAGE_RAISED || s->hl == DRAW_IMAGE_SUNKEN)
1228 {
1229 s->xgcv.foreground = s->face->foreground;
1230 s->xgcv.background = s->face->background;
1231 s->stippled_p = s->face->stipple != 0;
1232 }
1233 else
1234 emacs_abort ();
1235 }
1236
1237
1238
1239
1240
1241 static void
1242 pgtk_set_glyph_string_clipping (struct glyph_string *s, cairo_t * cr)
1243 {
1244 XRectangle r[2];
1245 int n = get_glyph_string_clip_rects (s, r, 2);
1246
1247 if (n > 0)
1248 {
1249 for (int i = 0; i < n; i++)
1250 {
1251 cairo_rectangle (cr, r[i].x, r[i].y, r[i].width, r[i].height);
1252 }
1253 cairo_clip (cr);
1254 }
1255 }
1256
1257
1258
1259
1260
1261 static void
1262 pgtk_set_glyph_string_clipping_exactly (struct glyph_string *src,
1263 struct glyph_string *dst, cairo_t * cr)
1264 {
1265 dst->clip[0].x = src->x;
1266 dst->clip[0].y = src->y;
1267 dst->clip[0].width = src->width;
1268 dst->clip[0].height = src->height;
1269 dst->num_clips = 1;
1270
1271 cairo_rectangle (cr, src->x, src->y, src->width, src->height);
1272 cairo_clip (cr);
1273 }
1274
1275
1276
1277
1278 static void
1279 pgtk_compute_glyph_string_overhangs (struct glyph_string *s)
1280 {
1281 if (s->cmp == NULL
1282 && (s->first_glyph->type == CHAR_GLYPH
1283 || s->first_glyph->type == COMPOSITE_GLYPH))
1284 {
1285 struct font_metrics metrics;
1286
1287 if (s->first_glyph->type == CHAR_GLYPH)
1288 {
1289 unsigned *code = alloca (sizeof (unsigned) * s->nchars);
1290 struct font *font = s->font;
1291 int i;
1292
1293 for (i = 0; i < s->nchars; i++)
1294 code[i] = s->char2b[i];
1295 font->driver->text_extents (font, code, s->nchars, &metrics);
1296 }
1297 else
1298 {
1299 Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
1300
1301 composition_gstring_width (gstring, s->cmp_from, s->cmp_to,
1302 &metrics);
1303 }
1304 s->right_overhang = (metrics.rbearing > metrics.width
1305 ? metrics.rbearing - metrics.width : 0);
1306 s->left_overhang = metrics.lbearing < 0 ? -metrics.lbearing : 0;
1307 }
1308 else if (s->cmp)
1309 {
1310 s->right_overhang = s->cmp->rbearing - s->cmp->pixel_width;
1311 s->left_overhang = -s->cmp->lbearing;
1312 }
1313 }
1314
1315
1316
1317 static void
1318 pgtk_clear_glyph_string_rect (struct glyph_string *s, int x, int y,
1319 int w, int h)
1320 {
1321 pgtk_fill_rectangle (s->f, s->xgcv.background, x, y, w, h,
1322 (s->first_glyph->type != STRETCH_GLYPH
1323 || s->hl != DRAW_CURSOR));
1324 }
1325
1326 static void
1327 fill_background_by_face (struct frame *f, struct face *face, int x, int y,
1328 int width, int height)
1329 {
1330 cairo_t *cr = pgtk_begin_cr_clip (f);
1331 double r, g, b, a;
1332
1333 cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
1334 cairo_rectangle (cr, x, y, width, height);
1335 cairo_clip (cr);
1336
1337 r = ((face->background >> 16) & 0xff) / 255.0;
1338 g = ((face->background >> 8) & 0xff) / 255.0;
1339 b = ((face->background >> 0) & 0xff) / 255.0;
1340 a = f->alpha_background;
1341 cairo_set_source_rgba (cr, r, g, b, a);
1342 cairo_paint (cr);
1343
1344 if (face->stipple != 0)
1345 {
1346 cairo_pattern_t *mask
1347 = FRAME_DISPLAY_INFO (f)->bitmaps[face->stipple - 1].pattern;
1348
1349 r = ((face->foreground >> 16) & 0xff) / 255.0;
1350 g = ((face->foreground >> 8) & 0xff) / 255.0;
1351 b = ((face->foreground >> 0) & 0xff) / 255.0;
1352 cairo_set_source_rgba (cr, r, g, b, a);
1353 cairo_mask (cr, mask);
1354 }
1355
1356 pgtk_end_cr_clip (f);
1357 }
1358
1359 static void
1360 fill_background (struct glyph_string *s, int x, int y, int width, int height)
1361 {
1362 fill_background_by_face (s->f, s->face, x, y, width, height);
1363 }
1364
1365
1366
1367
1368
1369
1370 static void
1371 pgtk_draw_glyph_string_background (struct glyph_string *s, bool force_p)
1372 {
1373
1374
1375 if (!s->background_filled_p)
1376 {
1377 int box_line_width = max (s->face->box_horizontal_line_width, 0);
1378
1379 if (s->stippled_p)
1380 {
1381
1382 fill_background (s, s->x, s->y + box_line_width,
1383 s->background_width,
1384 s->height - 2 * box_line_width);
1385 s->background_filled_p = true;
1386 }
1387 else if (FONT_HEIGHT (s->font) < s->height - 2 * box_line_width
1388
1389
1390
1391
1392 || FONT_TOO_HIGH (s->font)
1393 || s->font_not_found_p
1394 || s->extends_to_end_of_line_p || force_p)
1395 {
1396 pgtk_clear_glyph_string_rect (s, s->x, s->y + box_line_width,
1397 s->background_width,
1398 s->height - 2 * box_line_width);
1399 s->background_filled_p = true;
1400 }
1401 }
1402 }
1403
1404
1405 static void
1406 pgtk_draw_rectangle (struct frame *f, unsigned long color, int x, int y,
1407 int width, int height, bool respect_alpha_background)
1408 {
1409 cairo_t *cr;
1410
1411 cr = pgtk_begin_cr_clip (f);
1412 pgtk_set_cr_source_with_color (f, color, respect_alpha_background);
1413 cairo_rectangle (cr, x + 0.5, y + 0.5, width, height);
1414 cairo_set_line_width (cr, 1);
1415 cairo_stroke (cr);
1416 pgtk_end_cr_clip (f);
1417 }
1418
1419
1420 static void
1421 pgtk_draw_glyph_string_foreground (struct glyph_string *s)
1422 {
1423 int i, x;
1424
1425
1426
1427 if (s->face->box != FACE_NO_BOX && s->first_glyph->left_box_line_p)
1428 x = s->x + max (s->face->box_vertical_line_width, 0);
1429 else
1430 x = s->x;
1431
1432
1433
1434 if (s->font_not_found_p)
1435 {
1436 for (i = 0; i < s->nchars; ++i)
1437 {
1438 struct glyph *g = s->first_glyph + i;
1439 pgtk_draw_rectangle (s->f,
1440 s->face->foreground, x, s->y,
1441 g->pixel_width - 1, s->height - 1,
1442 false);
1443 x += g->pixel_width;
1444 }
1445 }
1446 else
1447 {
1448 struct font *font = s->font;
1449 int boff = font->baseline_offset;
1450 int y;
1451
1452 if (font->vertical_centering)
1453 boff = VCENTER_BASELINE_OFFSET (font, s->f) - boff;
1454
1455 y = s->ybase - boff;
1456 if (s->for_overlaps || (s->background_filled_p && s->hl != DRAW_CURSOR))
1457 font->driver->draw (s, 0, s->nchars, x, y, false);
1458 else
1459 font->driver->draw (s, 0, s->nchars, x, y, true);
1460 if (s->face->overstrike)
1461 font->driver->draw (s, 0, s->nchars, x + 1, y, false);
1462 }
1463 }
1464
1465
1466 static void
1467 pgtk_draw_composite_glyph_string_foreground (struct glyph_string *s)
1468 {
1469 int i, j, x;
1470 struct font *font = s->font;
1471
1472
1473
1474 if (s->face && s->face->box != FACE_NO_BOX
1475 && s->first_glyph->left_box_line_p)
1476 x = s->x + max (s->face->box_vertical_line_width, 0);
1477 else
1478 x = s->x;
1479
1480
1481
1482
1483
1484
1485
1486
1487 if (s->font_not_found_p)
1488 {
1489 if (s->cmp_from == 0)
1490 pgtk_draw_rectangle (s->f, s->face->foreground, x, s->y,
1491 s->width - 1, s->height - 1, false);
1492 }
1493 else if (!s->first_glyph->u.cmp.automatic)
1494 {
1495 int y = s->ybase;
1496
1497 for (i = 0, j = s->cmp_from; i < s->nchars; i++, j++)
1498
1499
1500 if (COMPOSITION_GLYPH (s->cmp, j) != '\t')
1501 {
1502 int xx = x + s->cmp->offsets[j * 2];
1503 int yy = y - s->cmp->offsets[j * 2 + 1];
1504
1505 font->driver->draw (s, j, j + 1, xx, yy, false);
1506 if (s->face->overstrike)
1507 font->driver->draw (s, j, j + 1, xx + 1, yy, false);
1508 }
1509 }
1510 else
1511 {
1512 Lisp_Object gstring = composition_gstring_from_id (s->cmp_id);
1513 Lisp_Object glyph;
1514 int y = s->ybase;
1515 int width = 0;
1516
1517 for (i = j = s->cmp_from; i < s->cmp_to; i++)
1518 {
1519 glyph = LGSTRING_GLYPH (gstring, i);
1520 if (NILP (LGLYPH_ADJUSTMENT (glyph)))
1521 width += LGLYPH_WIDTH (glyph);
1522 else
1523 {
1524 int xoff, yoff, wadjust;
1525
1526 if (j < i)
1527 {
1528 font->driver->draw (s, j, i, x, y, false);
1529 if (s->face->overstrike)
1530 font->driver->draw (s, j, i, x + 1, y, false);
1531 x += width;
1532 }
1533 xoff = LGLYPH_XOFF (glyph);
1534 yoff = LGLYPH_YOFF (glyph);
1535 wadjust = LGLYPH_WADJUST (glyph);
1536 font->driver->draw (s, i, i + 1, x + xoff, y + yoff, false);
1537 if (s->face->overstrike)
1538 font->driver->draw (s, i, i + 1, x + xoff + 1, y + yoff,
1539 false);
1540 x += wadjust;
1541 j = i + 1;
1542 width = 0;
1543 }
1544 }
1545 if (j < i)
1546 {
1547 font->driver->draw (s, j, i, x, y, false);
1548 if (s->face->overstrike)
1549 font->driver->draw (s, j, i, x + 1, y, false);
1550 }
1551 }
1552 }
1553
1554
1555
1556 static void
1557 pgtk_draw_glyphless_glyph_string_foreground (struct glyph_string *s)
1558 {
1559 struct glyph *glyph = s->first_glyph;
1560 unsigned char2b[8];
1561 int x, i, j;
1562
1563
1564
1565 if (s->face && s->face->box != FACE_NO_BOX
1566 && s->first_glyph->left_box_line_p)
1567 x = s->x + max (s->face->box_vertical_line_width, 0);
1568 else
1569 x = s->x;
1570
1571 s->char2b = char2b;
1572
1573 for (i = 0; i < s->nchars; i++, glyph++)
1574 {
1575 #ifdef GCC_LINT
1576 enum
1577 { PACIFY_GCC_BUG_81401 = 1 };
1578 #else
1579 enum
1580 { PACIFY_GCC_BUG_81401 = 0 };
1581 #endif
1582 char buf[7 + PACIFY_GCC_BUG_81401];
1583 char *str = NULL;
1584 int len = glyph->u.glyphless.len;
1585
1586 if (glyph->u.glyphless.method == GLYPHLESS_DISPLAY_ACRONYM)
1587 {
1588 if (len > 0
1589 && CHAR_TABLE_P (Vglyphless_char_display)
1590 &&
1591 (CHAR_TABLE_EXTRA_SLOTS (XCHAR_TABLE (Vglyphless_char_display))
1592 >= 1))
1593 {
1594 Lisp_Object acronym
1595 = (!glyph->u.glyphless.for_no_font
1596 ? CHAR_TABLE_REF (Vglyphless_char_display,
1597 glyph->u.glyphless.ch)
1598 : XCHAR_TABLE (Vglyphless_char_display)->extras[0]);
1599 if (CONSP (acronym))
1600 acronym = XCAR (acronym);
1601 if (STRINGP (acronym))
1602 str = SSDATA (acronym);
1603 }
1604 }
1605 else if (glyph->u.glyphless.method == GLYPHLESS_DISPLAY_HEX_CODE)
1606 {
1607 unsigned int ch = glyph->u.glyphless.ch;
1608 eassume (ch <= MAX_CHAR);
1609 sprintf (buf, "%0*X", ch < 0x10000 ? 4 : 6, ch);
1610 str = buf;
1611 }
1612
1613 if (str)
1614 {
1615 int upper_len = (len + 1) / 2;
1616
1617
1618 for (j = 0; j < len; j++)
1619 char2b[j]
1620 = s->font->driver->encode_char (s->font, str[j]) & 0xFFFF;
1621 s->font->driver->draw (s, 0, upper_len,
1622 x + glyph->slice.glyphless.upper_xoff,
1623 s->ybase + glyph->slice.glyphless.upper_yoff,
1624 false);
1625 s->font->driver->draw (s, upper_len, len,
1626 x + glyph->slice.glyphless.lower_xoff,
1627 s->ybase + glyph->slice.glyphless.lower_yoff,
1628 false);
1629 }
1630 if (glyph->u.glyphless.method != GLYPHLESS_DISPLAY_THIN_SPACE)
1631 pgtk_draw_rectangle (s->f, s->face->foreground,
1632 x, s->ybase - glyph->ascent,
1633 glyph->pixel_width - 1,
1634 glyph->ascent + glyph->descent - 1,
1635 false);
1636 x += glyph->pixel_width;
1637 }
1638
1639
1640
1641 s->char2b = NULL;
1642 }
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655 #define HIGHLIGHT_COLOR_DARK_BOOST_LIMIT 48000
1656
1657
1658
1659
1660
1661
1662
1663
1664 static void
1665 pgtk_compute_lighter_color (struct frame *f, unsigned long *pixel,
1666 double factor, int delta)
1667 {
1668 Emacs_Color color, new;
1669 long bright;
1670
1671
1672 color.pixel = *pixel;
1673 pgtk_query_color (f, &color);
1674
1675
1676 eassert (factor >= 0);
1677 new.red = min (0xffff, factor * color.red);
1678 new.green = min (0xffff, factor * color.green);
1679 new.blue = min (0xffff, factor * color.blue);
1680
1681
1682 bright = (2 * color.red + 3 * color.green + color.blue) / 6;
1683
1684
1685
1686 if (bright < HIGHLIGHT_COLOR_DARK_BOOST_LIMIT)
1687
1688
1689 {
1690
1691 double dimness = 1 - (double) bright / HIGHLIGHT_COLOR_DARK_BOOST_LIMIT;
1692
1693 int min_delta = delta * dimness * factor / 2;
1694
1695 if (factor < 1)
1696 {
1697 new.red = max (0, new.red - min_delta);
1698 new.green = max (0, new.green - min_delta);
1699 new.blue = max (0, new.blue - min_delta);
1700 }
1701 else
1702 {
1703 new.red = min (0xffff, min_delta + new.red);
1704 new.green = min (0xffff, min_delta + new.green);
1705 new.blue = min (0xffff, min_delta + new.blue);
1706 }
1707 }
1708
1709 new.pixel = (new.red >> 8 << 16
1710 | new.green >> 8 << 8
1711 | new.blue >> 8);
1712
1713 if (new.pixel == *pixel)
1714 {
1715
1716
1717 new.red = min (0xffff, delta + color.red);
1718 new.green = min (0xffff, delta + color.green);
1719 new.blue = min (0xffff, delta + color.blue);
1720 new.pixel = (new.red >> 8 << 16
1721 | new.green >> 8 << 8
1722 | new.blue >> 8);
1723 }
1724
1725 *pixel = new.pixel;
1726 }
1727
1728 static void
1729 pgtk_fill_trapezoid_for_relief (struct frame *f, unsigned long color, int x,
1730 int y, int width, int height, int top_p)
1731 {
1732 cairo_t *cr;
1733
1734 cr = pgtk_begin_cr_clip (f);
1735 pgtk_set_cr_source_with_color (f, color, false);
1736 cairo_move_to (cr, top_p ? x : x + height, y);
1737 cairo_line_to (cr, x, y + height);
1738 cairo_line_to (cr, top_p ? x + width - height : x + width, y + height);
1739 cairo_line_to (cr, x + width, y);
1740 cairo_fill (cr);
1741 pgtk_end_cr_clip (f);
1742 }
1743
1744 enum corners
1745 {
1746 CORNER_BOTTOM_RIGHT,
1747 CORNER_BOTTOM_LEFT,
1748 CORNER_TOP_LEFT,
1749 CORNER_TOP_RIGHT,
1750 CORNER_LAST
1751 };
1752
1753 static void
1754 pgtk_erase_corners_for_relief (struct frame *f, unsigned long color, int x,
1755 int y, int width, int height, double radius,
1756 double margin, int corners)
1757 {
1758 cairo_t *cr;
1759 int i;
1760
1761 cr = pgtk_begin_cr_clip (f);
1762 pgtk_set_cr_source_with_color (f, color, false);
1763 for (i = 0; i < CORNER_LAST; i++)
1764 if (corners & (1 << i))
1765 {
1766 double xm, ym, xc, yc;
1767
1768 if (i == CORNER_TOP_LEFT || i == CORNER_BOTTOM_LEFT)
1769 xm = x - margin, xc = xm + radius;
1770 else
1771 xm = x + width + margin, xc = xm - radius;
1772 if (i == CORNER_TOP_LEFT || i == CORNER_TOP_RIGHT)
1773 ym = y - margin, yc = ym + radius;
1774 else
1775 ym = y + height + margin, yc = ym - radius;
1776
1777 cairo_move_to (cr, xm, ym);
1778 cairo_arc (cr, xc, yc, radius, i * M_PI_2, (i + 1) * M_PI_2);
1779 }
1780 cairo_clip (cr);
1781 cairo_rectangle (cr, x, y, width, height);
1782 cairo_fill (cr);
1783 pgtk_end_cr_clip (f);
1784 }
1785
1786 static void
1787 pgtk_setup_relief_color (struct frame *f, struct relief *relief, double factor,
1788 int delta, unsigned long default_pixel)
1789 {
1790 Emacs_GC xgcv;
1791 struct pgtk_output *di = FRAME_X_OUTPUT (f);
1792 unsigned long pixel;
1793 unsigned long background = di->relief_background;
1794
1795
1796 xgcv.foreground = default_pixel;
1797 pixel = background;
1798 pgtk_compute_lighter_color (f, &pixel, factor, delta);
1799 xgcv.foreground = relief->pixel = pixel;
1800
1801 relief->xgcv = xgcv;
1802 }
1803
1804
1805 static void
1806 pgtk_setup_relief_colors (struct glyph_string *s)
1807 {
1808 struct pgtk_output *di = FRAME_X_OUTPUT (s->f);
1809 unsigned long color;
1810
1811 if (s->face->use_box_color_for_shadows_p)
1812 color = s->face->box_color;
1813 else if (s->first_glyph->type == IMAGE_GLYPH
1814 && s->img->pixmap
1815 && !IMAGE_BACKGROUND_TRANSPARENT (s->img, s->f, 0))
1816 color = IMAGE_BACKGROUND (s->img, s->f, 0);
1817 else
1818 {
1819
1820 color = s->xgcv.background;
1821 }
1822
1823 if (!di->relief_background_valid_p
1824 || di->relief_background != color)
1825 {
1826 di->relief_background_valid_p = true;
1827 di->relief_background = color;
1828 pgtk_setup_relief_color (s->f, &di->white_relief, 1.2, 0x8000,
1829 WHITE_PIX_DEFAULT (s->f));
1830 pgtk_setup_relief_color (s->f, &di->black_relief, 0.6, 0x4000,
1831 BLACK_PIX_DEFAULT (s->f));
1832 }
1833 }
1834
1835 static void
1836 pgtk_set_clip_rectangles (struct frame *f, cairo_t *cr,
1837 XRectangle *rectangles, int n)
1838 {
1839 if (n > 0)
1840 {
1841 for (int i = 0; i < n; i++)
1842 cairo_rectangle (cr, rectangles[i].x, rectangles[i].y,
1843 rectangles[i].width, rectangles[i].height);
1844 cairo_clip (cr);
1845 }
1846 }
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856 static void
1857 pgtk_draw_relief_rect (struct frame *f,
1858 int left_x, int top_y, int right_x, int bottom_y,
1859 int hwidth, int vwidth, bool raised_p, bool top_p,
1860 bool bot_p, bool left_p, bool right_p,
1861 XRectangle *clip_rect)
1862 {
1863 unsigned long top_left_color, bottom_right_color;
1864 int corners = 0;
1865
1866 cairo_t *cr = pgtk_begin_cr_clip (f);
1867
1868 if (raised_p)
1869 {
1870 top_left_color = FRAME_X_OUTPUT (f)->white_relief.xgcv.foreground;
1871 bottom_right_color = FRAME_X_OUTPUT (f)->black_relief.xgcv.foreground;
1872 }
1873 else
1874 {
1875 top_left_color = FRAME_X_OUTPUT (f)->black_relief.xgcv.foreground;
1876 bottom_right_color = FRAME_X_OUTPUT (f)->white_relief.xgcv.foreground;
1877 }
1878
1879 pgtk_set_clip_rectangles (f, cr, clip_rect, 1);
1880
1881 if (left_p)
1882 {
1883 pgtk_fill_rectangle (f, top_left_color, left_x, top_y,
1884 vwidth, bottom_y + 1 - top_y, false);
1885 if (top_p)
1886 corners |= 1 << CORNER_TOP_LEFT;
1887 if (bot_p)
1888 corners |= 1 << CORNER_BOTTOM_LEFT;
1889 }
1890 if (right_p)
1891 {
1892 pgtk_fill_rectangle (f, bottom_right_color, right_x + 1 - vwidth, top_y,
1893 vwidth, bottom_y + 1 - top_y, false);
1894 if (top_p)
1895 corners |= 1 << CORNER_TOP_RIGHT;
1896 if (bot_p)
1897 corners |= 1 << CORNER_BOTTOM_RIGHT;
1898 }
1899 if (top_p)
1900 {
1901 if (!right_p)
1902 pgtk_fill_rectangle (f, top_left_color, left_x, top_y,
1903 right_x + 1 - left_x, hwidth, false);
1904 else
1905 pgtk_fill_trapezoid_for_relief (f, top_left_color, left_x, top_y,
1906 right_x + 1 - left_x, hwidth, 1);
1907 }
1908 if (bot_p)
1909 {
1910 if (!left_p)
1911 pgtk_fill_rectangle (f, bottom_right_color, left_x,
1912 bottom_y + 1 - hwidth, right_x + 1 - left_x,
1913 hwidth, false);
1914 else
1915 pgtk_fill_trapezoid_for_relief (f, bottom_right_color,
1916 left_x, bottom_y + 1 - hwidth,
1917 right_x + 1 - left_x, hwidth, 0);
1918 }
1919 if (left_p && vwidth > 1)
1920 pgtk_fill_rectangle (f, bottom_right_color, left_x, top_y,
1921 1, bottom_y + 1 - top_y, false);
1922 if (top_p && hwidth > 1)
1923 pgtk_fill_rectangle (f, bottom_right_color, left_x, top_y,
1924 right_x + 1 - left_x, 1, false);
1925 if (corners)
1926 pgtk_erase_corners_for_relief (f, FRAME_BACKGROUND_PIXEL (f), left_x,
1927 top_y, right_x - left_x + 1,
1928 bottom_y - top_y + 1, 6, 1, corners);
1929
1930 pgtk_end_cr_clip (f);
1931 }
1932
1933
1934
1935
1936
1937
1938
1939
1940 static void
1941 pgtk_draw_box_rect (struct glyph_string *s, int left_x,
1942 int top_y, int right_x, int bottom_y, int hwidth,
1943 int vwidth, bool left_p, bool right_p,
1944 XRectangle * clip_rect)
1945 {
1946 unsigned long foreground_backup;
1947
1948 cairo_t *cr = pgtk_begin_cr_clip (s->f);
1949
1950 foreground_backup = s->xgcv.foreground;
1951 s->xgcv.foreground = s->face->box_color;
1952
1953 pgtk_set_clip_rectangles (s->f, cr, clip_rect, 1);
1954
1955
1956 pgtk_fill_rectangle (s->f, s->xgcv.foreground,
1957 left_x, top_y, right_x - left_x + 1, hwidth,
1958 false);
1959
1960
1961 if (left_p)
1962 pgtk_fill_rectangle (s->f, s->xgcv.foreground,
1963 left_x, top_y, vwidth, bottom_y - top_y + 1,
1964 false);
1965
1966
1967 pgtk_fill_rectangle (s->f, s->xgcv.foreground,
1968 left_x, bottom_y - hwidth + 1, right_x - left_x + 1,
1969 hwidth, false);
1970
1971
1972 if (right_p)
1973 pgtk_fill_rectangle (s->f, s->xgcv.foreground,
1974 right_x - vwidth + 1, top_y, vwidth,
1975 bottom_y - top_y + 1, false);
1976
1977 s->xgcv.foreground = foreground_backup;
1978
1979 pgtk_end_cr_clip (s->f);
1980 }
1981
1982
1983
1984
1985 static void
1986 pgtk_draw_glyph_string_box (struct glyph_string *s)
1987 {
1988 int hwidth, vwidth, left_x, right_x, top_y, bottom_y, last_x;
1989 bool raised_p, left_p, right_p;
1990 struct glyph *last_glyph;
1991 XRectangle clip_rect;
1992
1993 last_x = ((s->row->full_width_p && !s->w->pseudo_window_p)
1994 ? WINDOW_RIGHT_EDGE_X (s->w) : window_box_right (s->w, s->area));
1995
1996
1997 last_glyph = (s->cmp || s->img
1998 ? s->first_glyph : s->first_glyph + s->nchars - 1);
1999
2000 vwidth = eabs (s->face->box_vertical_line_width);
2001 hwidth = eabs (s->face->box_horizontal_line_width);
2002 raised_p = s->face->box == FACE_RAISED_BOX;
2003 left_x = s->x;
2004 right_x = (s->row->full_width_p && s->extends_to_end_of_line_p
2005 ? last_x - 1 : min (last_x, s->x + s->background_width) - 1);
2006 top_y = s->y;
2007 bottom_y = top_y + s->height - 1;
2008
2009 left_p = (s->first_glyph->left_box_line_p
2010 || (s->hl == DRAW_MOUSE_FACE
2011 && (s->prev == NULL || s->prev->hl != s->hl)));
2012 right_p = (last_glyph->right_box_line_p
2013 || (s->hl == DRAW_MOUSE_FACE
2014 && (s->next == NULL || s->next->hl != s->hl)));
2015
2016 get_glyph_string_clip_rect (s, &clip_rect);
2017
2018 if (s->face->box == FACE_SIMPLE_BOX)
2019 pgtk_draw_box_rect (s, left_x, top_y, right_x, bottom_y, hwidth,
2020 vwidth, left_p, right_p, &clip_rect);
2021 else
2022 {
2023 pgtk_setup_relief_colors (s);
2024 pgtk_draw_relief_rect (s->f, left_x, top_y, right_x, bottom_y, hwidth,
2025 vwidth, raised_p, true, true, left_p, right_p,
2026 &clip_rect);
2027 }
2028 }
2029
2030 static void
2031 pgtk_draw_horizontal_wave (struct frame *f, unsigned long color, int x, int y,
2032 int width, int height, int wave_length)
2033 {
2034 cairo_t *cr;
2035 double dx = wave_length, dy = height - 1;
2036 int xoffset, n;
2037
2038 cr = pgtk_begin_cr_clip (f);
2039 pgtk_set_cr_source_with_color (f, color, false);
2040 cairo_rectangle (cr, x, y, width, height);
2041 cairo_clip (cr);
2042
2043 if (x >= 0)
2044 {
2045 xoffset = x % (wave_length * 2);
2046 if (xoffset == 0)
2047 xoffset = wave_length * 2;
2048 }
2049 else
2050 xoffset = x % (wave_length * 2) + wave_length * 2;
2051 n = (width + xoffset) / wave_length + 1;
2052 if (xoffset > wave_length)
2053 {
2054 xoffset -= wave_length;
2055 --n;
2056 y += height - 1;
2057 dy = -dy;
2058 }
2059
2060 cairo_move_to (cr, x - xoffset + 0.5, y + 0.5);
2061 while (--n >= 0)
2062 {
2063 cairo_rel_line_to (cr, dx, dy);
2064 dy = -dy;
2065 }
2066 cairo_set_line_width (cr, 1);
2067 cairo_stroke (cr);
2068 pgtk_end_cr_clip (f);
2069 }
2070
2071 static void
2072 pgtk_draw_underwave (struct glyph_string *s, unsigned long color)
2073 {
2074 int wave_height = 3, wave_length = 2;
2075
2076 pgtk_draw_horizontal_wave (s->f, color, s->x, s->ybase - wave_height + 3,
2077 s->width, wave_height, wave_length);
2078 }
2079
2080
2081
2082 static void
2083 pgtk_draw_image_relief (struct glyph_string *s)
2084 {
2085 int x1, y1, thick;
2086 bool raised_p, top_p, bot_p, left_p, right_p;
2087 int extra_x, extra_y;
2088 XRectangle r;
2089 int x = s->x;
2090 int y = s->ybase - image_ascent (s->img, s->face, &s->slice);
2091
2092
2093
2094 if (s->face->box != FACE_NO_BOX
2095 && s->first_glyph->left_box_line_p
2096 && s->slice.x == 0)
2097 x += max (s->face->box_vertical_line_width, 0);
2098
2099
2100
2101 if (s->slice.x == 0)
2102 x += s->img->hmargin;
2103 if (s->slice.y == 0)
2104 y += s->img->vmargin;
2105
2106 if (s->hl == DRAW_IMAGE_SUNKEN
2107 || s->hl == DRAW_IMAGE_RAISED)
2108 {
2109 if (s->face->id == TAB_BAR_FACE_ID)
2110 thick = (tab_bar_button_relief < 0
2111 ? DEFAULT_TAB_BAR_BUTTON_RELIEF
2112 : min (tab_bar_button_relief, 1000000));
2113 else
2114 thick = (tool_bar_button_relief < 0
2115 ? DEFAULT_TOOL_BAR_BUTTON_RELIEF
2116 : min (tool_bar_button_relief, 1000000));
2117 raised_p = s->hl == DRAW_IMAGE_RAISED;
2118 }
2119 else
2120 {
2121 thick = eabs (s->img->relief);
2122 raised_p = s->img->relief > 0;
2123 }
2124
2125 x1 = x + s->slice.width - 1;
2126 y1 = y + s->slice.height - 1;
2127
2128 extra_x = extra_y = 0;
2129 if (s->face->id == TAB_BAR_FACE_ID)
2130 {
2131 if (CONSP (Vtab_bar_button_margin)
2132 && FIXNUMP (XCAR (Vtab_bar_button_margin))
2133 && FIXNUMP (XCDR (Vtab_bar_button_margin)))
2134 {
2135 extra_x = XFIXNUM (XCAR (Vtab_bar_button_margin)) - thick;
2136 extra_y = XFIXNUM (XCDR (Vtab_bar_button_margin)) - thick;
2137 }
2138 else if (FIXNUMP (Vtab_bar_button_margin))
2139 extra_x = extra_y = XFIXNUM (Vtab_bar_button_margin) - thick;
2140 }
2141
2142 if (s->face->id == TOOL_BAR_FACE_ID)
2143 {
2144 if (CONSP (Vtool_bar_button_margin)
2145 && FIXNUMP (XCAR (Vtool_bar_button_margin))
2146 && FIXNUMP (XCDR (Vtool_bar_button_margin)))
2147 {
2148 extra_x = XFIXNUM (XCAR (Vtool_bar_button_margin));
2149 extra_y = XFIXNUM (XCDR (Vtool_bar_button_margin));
2150 }
2151 else if (FIXNUMP (Vtool_bar_button_margin))
2152 extra_x = extra_y = XFIXNUM (Vtool_bar_button_margin);
2153 }
2154
2155 top_p = bot_p = left_p = right_p = false;
2156
2157 if (s->slice.x == 0)
2158 x -= thick + extra_x, left_p = true;
2159 if (s->slice.y == 0)
2160 y -= thick + extra_y, top_p = true;
2161 if (s->slice.x + s->slice.width == s->img->width)
2162 x1 += thick + extra_x, right_p = true;
2163 if (s->slice.y + s->slice.height == s->img->height)
2164 y1 += thick + extra_y, bot_p = true;
2165
2166 pgtk_setup_relief_colors (s);
2167 get_glyph_string_clip_rect (s, &r);
2168 pgtk_draw_relief_rect (s->f, x, y, x1, y1, thick, thick, raised_p,
2169 top_p, bot_p, left_p, right_p, &r);
2170 }
2171
2172
2173
2174
2175 static void
2176 pgtk_draw_glyph_string_bg_rect (struct glyph_string *s, int x, int y, int w,
2177 int h)
2178 {
2179 if (s->stippled_p)
2180 fill_background (s, x, y, w, h);
2181 else
2182 pgtk_clear_glyph_string_rect (s, x, y, w, h);
2183 }
2184
2185 static void
2186 pgtk_cr_draw_image (struct frame *f, Emacs_GC *gc, cairo_pattern_t *image,
2187 int src_x, int src_y, int width, int height,
2188 int dest_x, int dest_y, bool overlay_p)
2189 {
2190 cairo_t *cr = pgtk_begin_cr_clip (f);
2191
2192 if (overlay_p)
2193 cairo_rectangle (cr, dest_x, dest_y, width, height);
2194 else
2195 {
2196 pgtk_set_cr_source_with_gc_background (f, gc, false);
2197 cairo_rectangle (cr, dest_x, dest_y, width, height);
2198 cairo_fill_preserve (cr);
2199 }
2200
2201 cairo_translate (cr, dest_x - src_x, dest_y - src_y);
2202
2203 cairo_surface_t *surface;
2204 cairo_pattern_get_surface (image, &surface);
2205 cairo_format_t format = cairo_image_surface_get_format (surface);
2206 if (format != CAIRO_FORMAT_A8 && format != CAIRO_FORMAT_A1)
2207 {
2208 cairo_set_source (cr, image);
2209 cairo_fill (cr);
2210 }
2211 else
2212 {
2213 pgtk_set_cr_source_with_gc_foreground (f, gc, false);
2214 cairo_clip (cr);
2215 cairo_mask (cr, image);
2216 }
2217
2218 pgtk_end_cr_clip (f);
2219 }
2220
2221
2222
2223 static void
2224 pgtk_draw_image_foreground (struct glyph_string *s)
2225 {
2226 int x = s->x;
2227 int y = s->ybase - image_ascent (s->img, s->face, &s->slice);
2228
2229
2230
2231 if (s->face->box != FACE_NO_BOX
2232 && s->first_glyph->left_box_line_p
2233 && s->slice.x == 0)
2234 x += max (s->face->box_vertical_line_width, 0);
2235
2236
2237
2238 if (s->slice.x == 0)
2239 x += s->img->hmargin;
2240 if (s->slice.y == 0)
2241 y += s->img->vmargin;
2242
2243 if (s->img->cr_data)
2244 {
2245 cairo_t *cr = pgtk_begin_cr_clip (s->f);
2246 pgtk_set_glyph_string_clipping (s, cr);
2247 pgtk_cr_draw_image (s->f, &s->xgcv, s->img->cr_data,
2248 s->slice.x, s->slice.y, s->slice.width, s->slice.height,
2249 x, y, true);
2250 if (!s->img->mask)
2251 {
2252
2253
2254
2255
2256
2257
2258 if (s->hl == DRAW_CURSOR)
2259 {
2260 int relief = eabs (s->img->relief);
2261 pgtk_draw_rectangle (s->f, s->xgcv.foreground, x - relief,
2262 y - relief, s->slice.width + relief * 2 - 1,
2263 s->slice.height + relief * 2 - 1, false);
2264 }
2265 }
2266 pgtk_end_cr_clip (s->f);
2267 }
2268 else
2269
2270 pgtk_draw_rectangle (s->f, s->xgcv.foreground, x, y,
2271 s->slice.width - 1, s->slice.height - 1, false);
2272 }
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288 static void
2289 pgtk_draw_image_glyph_string (struct glyph_string *s)
2290 {
2291 int box_line_hwidth = max (s->face->box_vertical_line_width, 0);
2292 int box_line_vwidth = max (s->face->box_horizontal_line_width, 0);
2293 int height;
2294
2295 height = s->height;
2296 if (s->slice.y == 0)
2297 height -= box_line_vwidth;
2298 if (s->slice.y + s->slice.height >= s->img->height)
2299 height -= box_line_vwidth;
2300
2301
2302
2303
2304 s->stippled_p = s->face->stipple != 0;
2305 if (height > s->slice.height
2306 || s->img->hmargin
2307 || s->img->vmargin
2308 || s->img->mask
2309 || s->img->pixmap == 0
2310 || s->width != s->background_width)
2311 {
2312 int x = s->x;
2313 int y = s->y;
2314 int width = s->background_width;
2315
2316 if (s->first_glyph->left_box_line_p
2317 && s->slice.x == 0)
2318 {
2319 x += box_line_hwidth;
2320 width -= box_line_hwidth;
2321 }
2322
2323 if (s->slice.y == 0)
2324 y += box_line_vwidth;
2325
2326 pgtk_draw_glyph_string_bg_rect (s, x, y, width, height);
2327
2328 s->background_filled_p = true;
2329 }
2330
2331
2332 pgtk_draw_image_foreground (s);
2333
2334
2335 if (s->img->relief
2336 || s->hl == DRAW_IMAGE_RAISED
2337 || s->hl == DRAW_IMAGE_SUNKEN)
2338 pgtk_draw_image_relief (s);
2339 }
2340
2341
2342
2343 static void
2344 pgtk_draw_stretch_glyph_string (struct glyph_string *s)
2345 {
2346 eassert (s->first_glyph->type == STRETCH_GLYPH);
2347
2348 if (s->hl == DRAW_CURSOR && !x_stretch_cursor_p)
2349 {
2350
2351
2352 int width, background_width = s->background_width;
2353 int x = s->x;
2354
2355 if (!s->row->reversed_p)
2356 {
2357 int left_x = window_box_left_offset (s->w, TEXT_AREA);
2358
2359 if (x < left_x)
2360 {
2361 background_width -= left_x - x;
2362 x = left_x;
2363 }
2364 }
2365 else
2366 {
2367
2368
2369 int right_x = window_box_right (s->w, TEXT_AREA);
2370
2371 if (x + background_width > right_x)
2372 background_width -= x - right_x;
2373 x += background_width;
2374 }
2375 width = min (FRAME_COLUMN_WIDTH (s->f), background_width);
2376 if (s->row->reversed_p)
2377 x -= width;
2378
2379
2380 pgtk_draw_glyph_string_bg_rect (s, x, s->y, width, s->height);
2381
2382
2383 if (width < background_width)
2384 {
2385 int y = s->y;
2386 int w = background_width - width, h = s->height;
2387 XRectangle r;
2388 unsigned long color;
2389
2390 if (!s->row->reversed_p)
2391 x += width;
2392 else
2393 x = s->x;
2394 if (s->row->mouse_face_p && cursor_in_mouse_face_p (s->w))
2395 {
2396 pgtk_set_mouse_face_gc (s);
2397 color = s->xgcv.foreground;
2398 }
2399 else
2400 color = s->face->background;
2401
2402 cairo_t *cr = pgtk_begin_cr_clip (s->f);
2403
2404 get_glyph_string_clip_rect (s, &r);
2405 pgtk_set_clip_rectangles (s->f, cr, &r, 1);
2406
2407 if (s->face->stipple)
2408 fill_background (s, x, y, w, h);
2409 else
2410 pgtk_fill_rectangle (s->f, color, x, y, w, h,
2411 true);
2412
2413 pgtk_end_cr_clip (s->f);
2414 }
2415 }
2416 else if (!s->background_filled_p)
2417 {
2418 int background_width = s->background_width;
2419 int x = s->x, text_left_x = window_box_left (s->w, TEXT_AREA);
2420
2421
2422
2423 if (s->area == TEXT_AREA
2424 && x < text_left_x && !s->row->mode_line_p)
2425 {
2426 background_width -= text_left_x - x;
2427 x = text_left_x;
2428 }
2429
2430 if (background_width > 0)
2431 pgtk_draw_glyph_string_bg_rect (s, x, s->y, background_width, s->height);
2432 }
2433
2434 s->background_filled_p = true;
2435 }
2436
2437 static void
2438 pgtk_draw_glyph_string (struct glyph_string *s)
2439 {
2440 bool relief_drawn_p = false;
2441
2442
2443
2444
2445 if (s->next && s->right_overhang && !s->for_overlaps)
2446 {
2447 int width;
2448 struct glyph_string *next;
2449
2450 for (width = 0, next = s->next;
2451 next && width < s->right_overhang;
2452 width += next->width, next = next->next)
2453 if (next->first_glyph->type != IMAGE_GLYPH)
2454 {
2455 cairo_t *cr = pgtk_begin_cr_clip (next->f);
2456 pgtk_set_glyph_string_gc (next);
2457 pgtk_set_glyph_string_clipping (next, cr);
2458 if (next->first_glyph->type == STRETCH_GLYPH)
2459 pgtk_draw_stretch_glyph_string (next);
2460 else
2461 pgtk_draw_glyph_string_background (next, true);
2462 next->num_clips = 0;
2463 pgtk_end_cr_clip (next->f);
2464 }
2465 }
2466
2467
2468 pgtk_set_glyph_string_gc (s);
2469
2470 cairo_t *cr = pgtk_begin_cr_clip (s->f);
2471
2472
2473
2474 if (!s->for_overlaps
2475 && s->face->box != FACE_NO_BOX
2476 && (s->first_glyph->type == CHAR_GLYPH
2477 || s->first_glyph->type == COMPOSITE_GLYPH))
2478
2479 {
2480 pgtk_set_glyph_string_clipping (s, cr);
2481 pgtk_draw_glyph_string_background (s, true);
2482 pgtk_draw_glyph_string_box (s);
2483 pgtk_set_glyph_string_clipping (s, cr);
2484 relief_drawn_p = true;
2485 }
2486 else if (!s->clip_head
2487 && !s->clip_tail
2488 && ((s->prev && s->prev->hl != s->hl && s->left_overhang)
2489 || (s->next && s->next->hl != s->hl && s->right_overhang)))
2490
2491
2492
2493 pgtk_set_glyph_string_clipping_exactly (s, s, cr);
2494 else
2495 pgtk_set_glyph_string_clipping (s, cr);
2496
2497 switch (s->first_glyph->type)
2498 {
2499 case IMAGE_GLYPH:
2500 pgtk_draw_image_glyph_string (s);
2501 break;
2502
2503 case XWIDGET_GLYPH:
2504 x_draw_xwidget_glyph_string (s);
2505 break;
2506
2507 case STRETCH_GLYPH:
2508 pgtk_draw_stretch_glyph_string (s);
2509 break;
2510
2511 case CHAR_GLYPH:
2512 if (s->for_overlaps)
2513 s->background_filled_p = true;
2514 else
2515 pgtk_draw_glyph_string_background (s, false);
2516 pgtk_draw_glyph_string_foreground (s);
2517 break;
2518
2519 case COMPOSITE_GLYPH:
2520 if (s->for_overlaps || (s->cmp_from > 0
2521 && !s->first_glyph->u.cmp.automatic))
2522 s->background_filled_p = true;
2523 else
2524 pgtk_draw_glyph_string_background (s, true);
2525 pgtk_draw_composite_glyph_string_foreground (s);
2526 break;
2527
2528 case GLYPHLESS_GLYPH:
2529 if (s->for_overlaps)
2530 s->background_filled_p = true;
2531 else
2532 pgtk_draw_glyph_string_background (s, true);
2533 pgtk_draw_glyphless_glyph_string_foreground (s);
2534 break;
2535
2536 default:
2537 emacs_abort ();
2538 }
2539
2540 if (!s->for_overlaps)
2541 {
2542
2543 if (!relief_drawn_p && s->face->box != FACE_NO_BOX)
2544 pgtk_draw_glyph_string_box (s);
2545
2546
2547 if (s->face->underline)
2548 {
2549 if (s->face->underline == FACE_UNDER_WAVE)
2550 {
2551 if (s->face->underline_defaulted_p)
2552 pgtk_draw_underwave (s, s->xgcv.foreground);
2553 else
2554 pgtk_draw_underwave (s, s->face->underline_color);
2555 }
2556 else if (s->face->underline == FACE_UNDER_LINE)
2557 {
2558 unsigned long thickness, position;
2559 int y;
2560
2561 if (s->prev
2562 && s->prev->face->underline == FACE_UNDER_LINE
2563 && (s->prev->face->underline_at_descent_line_p
2564 == s->face->underline_at_descent_line_p)
2565 && (s->prev->face->underline_pixels_above_descent_line
2566 == s->face->underline_pixels_above_descent_line))
2567 {
2568
2569 thickness = s->prev->underline_thickness;
2570 position = s->prev->underline_position;
2571 }
2572 else
2573 {
2574 struct font *font = font_for_underline_metrics (s);
2575
2576
2577 if (font && font->underline_thickness > 0)
2578 thickness = font->underline_thickness;
2579 else
2580 thickness = 1;
2581 if ((x_underline_at_descent_line
2582 || s->face->underline_at_descent_line_p))
2583 position = ((s->height - thickness)
2584 - (s->ybase - s->y)
2585 - s->face->underline_pixels_above_descent_line);
2586 else
2587 {
2588
2589
2590
2591
2592
2593
2594
2595
2596 if (x_use_underline_position_properties
2597 && font && font->underline_position >= 0)
2598 position = font->underline_position;
2599 else if (font)
2600 position = (font->descent + 1) / 2;
2601 else
2602 position = underline_minimum_offset;
2603 }
2604
2605
2606
2607 if (!s->face->underline_pixels_above_descent_line)
2608 position = max (position, underline_minimum_offset);
2609 }
2610
2611
2612 if (s->y + s->height <= s->ybase + position)
2613 position = (s->height - 1) - (s->ybase - s->y);
2614 if (s->y + s->height < s->ybase + position + thickness)
2615 thickness = (s->y + s->height) - (s->ybase + position);
2616 s->underline_thickness = thickness;
2617 s->underline_position = position;
2618 y = s->ybase + position;
2619 if (s->face->underline_defaulted_p)
2620 pgtk_fill_rectangle (s->f, s->xgcv.foreground,
2621 s->x, y, s->width, thickness,
2622 false);
2623 else
2624 {
2625 pgtk_fill_rectangle (s->f, s->face->underline_color,
2626 s->x, y, s->width, thickness,
2627 false);
2628 }
2629 }
2630 }
2631
2632 if (s->face->overline_p)
2633 {
2634 unsigned long dy = 0, h = 1;
2635
2636 if (s->face->overline_color_defaulted_p)
2637 pgtk_fill_rectangle (s->f, s->xgcv.foreground, s->x, s->y + dy,
2638 s->width, h, false);
2639 else
2640 pgtk_fill_rectangle (s->f, s->face->overline_color, s->x,
2641 s->y + dy, s->width, h, false);
2642 }
2643
2644
2645 if (s->face->strike_through_p)
2646 {
2647
2648
2649
2650
2651
2652 int glyph_y = s->ybase - s->first_glyph->ascent;
2653 int glyph_height = s->first_glyph->ascent + s->first_glyph->descent;
2654
2655
2656 unsigned long h = 1;
2657 unsigned long dy = (glyph_height - h) / 2;
2658
2659 if (s->face->strike_through_color_defaulted_p)
2660 pgtk_fill_rectangle (s->f, s->xgcv.foreground, s->x, glyph_y + dy,
2661 s->width, h, false);
2662 else
2663 pgtk_fill_rectangle (s->f, s->face->strike_through_color, s->x,
2664 glyph_y + dy, s->width, h, false);
2665 }
2666
2667 if (s->prev)
2668 {
2669 struct glyph_string *prev;
2670
2671 for (prev = s->prev; prev; prev = prev->prev)
2672 if (prev->hl != s->hl
2673 && prev->x + prev->width + prev->right_overhang > s->x)
2674 {
2675
2676
2677 enum draw_glyphs_face save = prev->hl;
2678
2679 prev->hl = s->hl;
2680 pgtk_set_glyph_string_gc (prev);
2681 cairo_save (cr);
2682 pgtk_set_glyph_string_clipping_exactly (s, prev, cr);
2683 if (prev->first_glyph->type == CHAR_GLYPH)
2684 pgtk_draw_glyph_string_foreground (prev);
2685 else
2686 pgtk_draw_composite_glyph_string_foreground (prev);
2687 prev->hl = save;
2688 prev->num_clips = 0;
2689 cairo_restore (cr);
2690 }
2691 }
2692
2693 if (s->next)
2694 {
2695 struct glyph_string *next;
2696
2697 for (next = s->next; next; next = next->next)
2698 if (next->hl != s->hl
2699 && next->x - next->left_overhang < s->x + s->width)
2700 {
2701
2702
2703 enum draw_glyphs_face save = next->hl;
2704
2705 next->hl = s->hl;
2706 pgtk_set_glyph_string_gc (next);
2707 cairo_save (cr);
2708 pgtk_set_glyph_string_clipping_exactly (s, next, cr);
2709 if (next->first_glyph->type == CHAR_GLYPH)
2710 pgtk_draw_glyph_string_foreground (next);
2711 else
2712 pgtk_draw_composite_glyph_string_foreground (next);
2713 cairo_restore (cr);
2714 next->hl = save;
2715 next->num_clips = 0;
2716 next->clip_head = s->next;
2717 }
2718 }
2719 }
2720
2721
2722
2723 if (!s->row->stipple_p)
2724 s->row->stipple_p = s->face->stipple;
2725
2726
2727 pgtk_end_cr_clip (s->f);
2728 s->num_clips = 0;
2729 }
2730
2731
2732
2733 static void
2734 pgtk_define_frame_cursor (struct frame *f, Emacs_Cursor cursor)
2735 {
2736 if (!f->pointer_invisible && FRAME_X_OUTPUT (f)->current_cursor != cursor)
2737 gdk_window_set_cursor (gtk_widget_get_window (FRAME_GTK_WIDGET (f)),
2738 cursor);
2739 FRAME_X_OUTPUT (f)->current_cursor = cursor;
2740 }
2741
2742 static void
2743 pgtk_after_update_window_line (struct window *w,
2744 struct glyph_row *desired_row)
2745 {
2746 struct frame *f;
2747 int width, height;
2748
2749
2750 eassert (w);
2751
2752 if (!desired_row->mode_line_p && !w->pseudo_window_p)
2753 desired_row->redraw_fringe_bitmaps_p = 1;
2754
2755
2756
2757 if (windows_or_buffers_changed
2758 && desired_row->full_width_p
2759 && (f = XFRAME (w->frame),
2760 width = FRAME_INTERNAL_BORDER_WIDTH (f),
2761 width != 0) && (height = desired_row->visible_height, height > 0))
2762 {
2763 int y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, desired_row->y));
2764
2765 block_input ();
2766 pgtk_clear_frame_area (f, 0, y, width, height);
2767 pgtk_clear_frame_area (f,
2768 FRAME_PIXEL_WIDTH (f) - width, y, width, height);
2769 unblock_input ();
2770 }
2771 }
2772
2773 static void
2774 pgtk_clear_frame_area (struct frame *f, int x, int y, int width, int height)
2775 {
2776 pgtk_clear_area (f, x, y, width, height);
2777 }
2778
2779
2780
2781 static void
2782 pgtk_draw_hollow_cursor (struct window *w, struct glyph_row *row)
2783 {
2784 struct frame *f = XFRAME (WINDOW_FRAME (w));
2785 int x, y, wd, h;
2786 struct glyph *cursor_glyph;
2787
2788
2789
2790 cursor_glyph = get_phys_cursor_glyph (w);
2791 if (cursor_glyph == NULL)
2792 return;
2793
2794
2795 get_phys_cursor_geometry (w, row, cursor_glyph, &x, &y, &h);
2796 wd = w->phys_cursor_width - 1;
2797
2798
2799
2800 cairo_t *cr = pgtk_begin_cr_clip (f);
2801 pgtk_set_cr_source_with_color (f, FRAME_X_OUTPUT (f)->cursor_color, false);
2802
2803
2804
2805
2806 if ((cursor_glyph->resolved_level & 1) != 0
2807 && cursor_glyph->pixel_width > wd)
2808 {
2809 x += cursor_glyph->pixel_width - wd;
2810 if (wd > 0)
2811 wd -= 1;
2812 }
2813
2814 pgtk_clip_to_row (w, row, TEXT_AREA, cr);
2815 pgtk_draw_rectangle (f, FRAME_X_OUTPUT (f)->cursor_color,
2816 x, y, wd, h - 1, false);
2817 pgtk_end_cr_clip (f);
2818 }
2819
2820
2821
2822
2823
2824
2825
2826
2827 static void
2828 pgtk_draw_bar_cursor (struct window *w, struct glyph_row *row, int width,
2829 enum text_cursor_kinds kind)
2830 {
2831 struct frame *f = XFRAME (w->frame);
2832 struct glyph *cursor_glyph;
2833
2834
2835
2836
2837 cursor_glyph = get_phys_cursor_glyph (w);
2838 if (cursor_glyph == NULL)
2839 return;
2840
2841
2842 if (cursor_glyph->type == XWIDGET_GLYPH)
2843 return;
2844
2845
2846
2847
2848 if (cursor_glyph->type == IMAGE_GLYPH)
2849 {
2850 struct glyph_row *r;
2851 r = MATRIX_ROW (w->current_matrix, w->phys_cursor.vpos);
2852 draw_phys_cursor_glyph (w, r, DRAW_CURSOR);
2853 }
2854 else
2855 {
2856 struct face *face = FACE_FROM_ID (f, cursor_glyph->face_id);
2857 unsigned long color;
2858
2859 cairo_t *cr = pgtk_begin_cr_clip (f);
2860
2861
2862
2863
2864
2865
2866 if (face->background == FRAME_X_OUTPUT (f)->cursor_color)
2867 color = face->foreground;
2868 else
2869 color = FRAME_X_OUTPUT (f)->cursor_color;
2870
2871 pgtk_clip_to_row (w, row, TEXT_AREA, cr);
2872
2873 if (kind == BAR_CURSOR)
2874 {
2875 int x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
2876
2877 if (width < 0)
2878 width = FRAME_CURSOR_WIDTH (f);
2879 width = min (cursor_glyph->pixel_width, width);
2880
2881 w->phys_cursor_width = width;
2882
2883
2884
2885 if ((cursor_glyph->resolved_level & 1) != 0)
2886 x += cursor_glyph->pixel_width - width;
2887
2888 pgtk_fill_rectangle (f, color, x,
2889 WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y),
2890 width, row->height, false);
2891 }
2892 else
2893 {
2894 int dummy_x, dummy_y, dummy_h;
2895 int x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, w->phys_cursor.x);
2896
2897 if (width < 0)
2898 width = row->height;
2899
2900 width = min (row->height, width);
2901
2902 get_phys_cursor_geometry (w, row, cursor_glyph, &dummy_x,
2903 &dummy_y, &dummy_h);
2904
2905 if ((cursor_glyph->resolved_level & 1) != 0
2906 && cursor_glyph->pixel_width > w->phys_cursor_width - 1)
2907 x += cursor_glyph->pixel_width - w->phys_cursor_width + 1;
2908 pgtk_fill_rectangle (f, color, x,
2909 WINDOW_TO_FRAME_PIXEL_Y (w, w->phys_cursor.y +
2910 row->height - width),
2911 w->phys_cursor_width - 1, width, false);
2912 }
2913
2914 pgtk_end_cr_clip (f);
2915 }
2916 }
2917
2918
2919
2920 static void
2921 pgtk_draw_window_cursor (struct window *w, struct glyph_row *glyph_row, int x,
2922 int y, enum text_cursor_kinds cursor_type,
2923 int cursor_width, bool on_p, bool active_p)
2924 {
2925 struct frame *f = XFRAME (w->frame);
2926
2927 if (on_p)
2928 {
2929 w->phys_cursor_type = cursor_type;
2930 w->phys_cursor_on_p = true;
2931
2932 if (glyph_row->exact_window_width_line_p
2933 && (glyph_row->reversed_p
2934 ? (w->phys_cursor.hpos < 0)
2935 : (w->phys_cursor.hpos >= glyph_row->used[TEXT_AREA])))
2936 {
2937 glyph_row->cursor_in_fringe_p = true;
2938 draw_fringe_bitmap (w, glyph_row, glyph_row->reversed_p);
2939 }
2940 else
2941 {
2942 switch (cursor_type)
2943 {
2944 case HOLLOW_BOX_CURSOR:
2945 pgtk_draw_hollow_cursor (w, glyph_row);
2946 break;
2947
2948 case FILLED_BOX_CURSOR:
2949 draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
2950 break;
2951
2952 case BAR_CURSOR:
2953 pgtk_draw_bar_cursor (w, glyph_row, cursor_width, BAR_CURSOR);
2954 break;
2955
2956 case HBAR_CURSOR:
2957 pgtk_draw_bar_cursor (w, glyph_row, cursor_width, HBAR_CURSOR);
2958 break;
2959
2960 case NO_CURSOR:
2961 w->phys_cursor_width = 0;
2962 break;
2963
2964 default:
2965 emacs_abort ();
2966 }
2967 }
2968
2969 if (w == XWINDOW (f->selected_window))
2970 {
2971 int frame_x = (WINDOW_TO_FRAME_PIXEL_X (w, x)
2972 + WINDOW_LEFT_FRINGE_WIDTH (w)
2973 + WINDOW_LEFT_MARGIN_WIDTH (w));
2974 int frame_y = WINDOW_TO_FRAME_PIXEL_Y (w, y);
2975 pgtk_im_set_cursor_location (f, frame_x, frame_y,
2976 w->phys_cursor_width,
2977 w->phys_cursor_height);
2978 }
2979 }
2980
2981 }
2982
2983 static void
2984 pgtk_copy_bits (struct frame *f, cairo_rectangle_t *src_rect,
2985 cairo_rectangle_t *dst_rect)
2986 {
2987 cairo_t *cr;
2988 cairo_surface_t *surface;
2989
2990 surface
2991 = cairo_surface_create_similar (FRAME_CR_SURFACE (f),
2992 CAIRO_CONTENT_COLOR_ALPHA,
2993 (int) src_rect->width,
2994 (int) src_rect->height);
2995
2996 cr = cairo_create (surface);
2997 cairo_set_source_surface (cr, FRAME_CR_SURFACE (f), -src_rect->x,
2998 -src_rect->y);
2999 cairo_rectangle (cr, 0, 0, src_rect->width, src_rect->height);
3000 cairo_clip (cr);
3001 cairo_paint (cr);
3002 cairo_destroy (cr);
3003
3004 cr = pgtk_begin_cr_clip (f);
3005 cairo_set_source_surface (cr, surface, dst_rect->x, dst_rect->y);
3006 cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
3007 cairo_rectangle (cr, dst_rect->x, dst_rect->y, dst_rect->width,
3008 dst_rect->height);
3009 cairo_clip (cr);
3010 cairo_paint (cr);
3011 pgtk_end_cr_clip (f);
3012
3013 cairo_surface_destroy (surface);
3014 }
3015
3016
3017
3018 static void
3019 pgtk_scroll_run (struct window *w, struct run *run)
3020 {
3021 struct frame *f = XFRAME (w->frame);
3022 int x, y, width, height, from_y, to_y, bottom_y;
3023
3024
3025
3026
3027 window_box (w, ANY_AREA, &x, &y, &width, &height);
3028
3029 from_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->current_y);
3030 to_y = WINDOW_TO_FRAME_PIXEL_Y (w, run->desired_y);
3031 bottom_y = y + height;
3032
3033 if (to_y < from_y)
3034 {
3035
3036
3037 if (from_y + run->height > bottom_y)
3038 height = bottom_y - from_y;
3039 else
3040 height = run->height;
3041 }
3042 else
3043 {
3044
3045
3046 if (to_y + run->height > bottom_y)
3047 height = bottom_y - to_y;
3048 else
3049 height = run->height;
3050 }
3051
3052 block_input ();
3053
3054 #ifdef HAVE_XWIDGETS
3055
3056 GtkWidget *tem, *parent = FRAME_GTK_WIDGET (f);
3057 GList *children = gtk_container_get_children (GTK_CONTAINER (parent));
3058 GList *iter;
3059 struct xwidget_view *view;
3060
3061 for (iter = children; iter; iter = iter->next)
3062 {
3063 tem = iter->data;
3064 view = g_object_get_data (G_OBJECT (tem), XG_XWIDGET_VIEW);
3065
3066 if (view && !view->hidden)
3067 {
3068 int window_y = view->y + view->clip_top;
3069 int window_height = view->clip_bottom - view->clip_top;
3070
3071 Emacs_Rectangle r1, r2, result;
3072 r1.x = w->pixel_left;
3073 r1.y = from_y;
3074 r1.width = w->pixel_width;
3075 r1.height = height;
3076 r2 = r1;
3077 r2.y = window_y;
3078 r2.height = window_height;
3079
3080
3081 if (window_height == 0)
3082 {
3083 view->hidden = true;
3084 gtk_widget_hide (tem);
3085 continue;
3086 }
3087
3088 bool intersects_p =
3089 gui_intersect_rectangles (&r1, &r2, &result);
3090
3091 if (XWINDOW (view->w) == w && intersects_p)
3092 {
3093 int y = view->y + (to_y - from_y);
3094 int text_area_x, text_area_y, text_area_width, text_area_height;
3095 int clip_top, clip_bottom;
3096
3097 window_box (w, view->area, &text_area_x, &text_area_y,
3098 &text_area_width, &text_area_height);
3099
3100 view->y = y;
3101
3102 clip_top = 0;
3103 clip_bottom = XXWIDGET (view->model)->height;
3104
3105 if (y < text_area_y)
3106 clip_top = text_area_y - y;
3107
3108 if ((y + clip_bottom) > (text_area_y + text_area_height))
3109 {
3110 clip_bottom -= (y + clip_bottom) - (text_area_y + text_area_height);
3111 }
3112
3113 view->clip_top = clip_top;
3114 view->clip_bottom = clip_bottom;
3115
3116
3117
3118 if ((view->clip_bottom - view->clip_top) <= 0)
3119 {
3120 view->hidden = true;
3121 gtk_widget_hide (tem);
3122 }
3123 else
3124 {
3125 gtk_fixed_move (GTK_FIXED (FRAME_GTK_WIDGET (f)),
3126 tem, view->x + view->clip_left,
3127 view->y + view->clip_top);
3128 gtk_widget_set_size_request (tem, view->clip_right - view->clip_left,
3129 view->clip_bottom - view->clip_top);
3130 gtk_widget_queue_allocate (tem);
3131 }
3132 }
3133 }
3134 }
3135
3136 g_list_free (children);
3137 #endif
3138
3139
3140 gui_clear_cursor (w);
3141
3142 {
3143 cairo_rectangle_t src_rect = { x, from_y, width, height };
3144 cairo_rectangle_t dst_rect = { x, to_y, width, height };
3145 pgtk_copy_bits (f, &src_rect, &dst_rect);
3146 }
3147
3148 unblock_input ();
3149 }
3150
3151
3152
3153
3154
3155 static bool
3156 pgtk_bitmap_icon (struct frame *f, Lisp_Object file)
3157 {
3158 ptrdiff_t bitmap_id;
3159
3160 if (FRAME_GTK_WIDGET (f) == 0)
3161 return true;
3162
3163
3164 if (f->output_data.pgtk->icon_bitmap > 0)
3165 image_destroy_bitmap (f, f->output_data.pgtk->icon_bitmap);
3166 f->output_data.pgtk->icon_bitmap = 0;
3167
3168 if (STRINGP (file))
3169 {
3170
3171
3172 if (xg_set_icon (f, file))
3173 return false;
3174 bitmap_id = image_create_bitmap_from_file (f, file);
3175 }
3176 else
3177 {
3178
3179 if (FRAME_DISPLAY_INFO (f)->icon_bitmap_id < 0)
3180 {
3181 ptrdiff_t rc = -1;
3182
3183 if (xg_set_icon (f, xg_default_icon_file)
3184 || xg_set_icon_from_xpm_data (f, gnu_xpm_bits))
3185 {
3186 FRAME_DISPLAY_INFO (f)->icon_bitmap_id = -2;
3187 return false;
3188 }
3189
3190
3191 if (rc == -1)
3192 {
3193 rc = image_create_bitmap_from_data (f,
3194 (char *) gnu_xbm_bits,
3195 gnu_xbm_width,
3196 gnu_xbm_height);
3197 if (rc == -1)
3198 return true;
3199
3200 FRAME_DISPLAY_INFO (f)->icon_bitmap_id = rc;
3201 }
3202 }
3203
3204
3205
3206
3207
3208 image_reference_bitmap (f, FRAME_DISPLAY_INFO (f)->icon_bitmap_id);
3209
3210 bitmap_id = FRAME_DISPLAY_INFO (f)->icon_bitmap_id;
3211 }
3212
3213 if (FRAME_DISPLAY_INFO (f)->bitmaps[bitmap_id - 1].img != NULL)
3214 gtk_window_set_icon (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)),
3215 FRAME_DISPLAY_INFO (f)->bitmaps[bitmap_id - 1].img);
3216
3217 f->output_data.pgtk->icon_bitmap = bitmap_id;
3218
3219 return false;
3220 }
3221
3222
3223
3224
3225
3226 bool
3227 pgtk_text_icon (struct frame *f, const char *icon_name)
3228 {
3229 if (FRAME_GTK_OUTER_WIDGET (f))
3230 {
3231 gtk_window_set_icon (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)), NULL);
3232 gtk_window_set_title (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)), icon_name);
3233 }
3234
3235 return false;
3236 }
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248 static void
3249 pgtk_update_begin (struct frame *f)
3250 {
3251 pgtk_clear_under_internal_border (f);
3252 }
3253
3254
3255
3256 static void
3257 pgtk_draw_vertical_window_border (struct window *w, int x, int y0, int y1)
3258 {
3259 struct frame *f = XFRAME (WINDOW_FRAME (w));
3260 struct face *face;
3261 cairo_t *cr;
3262
3263 cr = pgtk_begin_cr_clip (f);
3264
3265 face = FACE_FROM_ID_OR_NULL (f, VERTICAL_BORDER_FACE_ID);
3266 if (face)
3267 pgtk_set_cr_source_with_color (f, face->foreground, false);
3268
3269 cairo_rectangle (cr, x, y0, 1, y1 - y0);
3270 cairo_fill (cr);
3271
3272 pgtk_end_cr_clip (f);
3273 }
3274
3275
3276
3277 static void
3278 pgtk_draw_window_divider (struct window *w, int x0, int x1, int y0, int y1)
3279 {
3280 struct frame *f = XFRAME (WINDOW_FRAME (w));
3281 struct face *face = FACE_FROM_ID_OR_NULL (f, WINDOW_DIVIDER_FACE_ID);
3282 struct face *face_first
3283 = FACE_FROM_ID_OR_NULL (f, WINDOW_DIVIDER_FIRST_PIXEL_FACE_ID);
3284 struct face *face_last
3285 = FACE_FROM_ID_OR_NULL (f, WINDOW_DIVIDER_LAST_PIXEL_FACE_ID);
3286 unsigned long color = face ? face->foreground : FRAME_FOREGROUND_PIXEL (f);
3287 unsigned long color_first = (face_first
3288 ? face_first->foreground
3289 : FRAME_FOREGROUND_PIXEL (f));
3290 unsigned long color_last = (face_last
3291 ? face_last->foreground
3292 : FRAME_FOREGROUND_PIXEL (f));
3293 cairo_t *cr = pgtk_begin_cr_clip (f);
3294
3295 if (y1 - y0 > x1 - x0 && x1 - x0 > 2)
3296
3297 {
3298 pgtk_set_cr_source_with_color (f, color_first, false);
3299 cairo_rectangle (cr, x0, y0, 1, y1 - y0);
3300 cairo_fill (cr);
3301 pgtk_set_cr_source_with_color (f, color, false);
3302 cairo_rectangle (cr, x0 + 1, y0, x1 - x0 - 2, y1 - y0);
3303 cairo_fill (cr);
3304 pgtk_set_cr_source_with_color (f, color_last, false);
3305 cairo_rectangle (cr, x1 - 1, y0, 1, y1 - y0);
3306 cairo_fill (cr);
3307 }
3308 else if (x1 - x0 > y1 - y0 && y1 - y0 > 3)
3309
3310 {
3311 pgtk_set_cr_source_with_color (f, color_first, false);
3312 cairo_rectangle (cr, x0, y0, x1 - x0, 1);
3313 cairo_fill (cr);
3314 pgtk_set_cr_source_with_color (f, color, false);
3315 cairo_rectangle (cr, x0, y0 + 1, x1 - x0, y1 - y0 - 2);
3316 cairo_fill (cr);
3317 pgtk_set_cr_source_with_color (f, color_last, false);
3318 cairo_rectangle (cr, x0, y1 - 1, x1 - x0, 1);
3319 cairo_fill (cr);
3320 }
3321 else
3322 {
3323 pgtk_set_cr_source_with_color (f, color, false);
3324 cairo_rectangle (cr, x0, y0, x1 - x0, y1 - y0);
3325 cairo_fill (cr);
3326 }
3327
3328 pgtk_end_cr_clip (f);
3329 }
3330
3331
3332
3333
3334 static void
3335 pgtk_update_end (struct frame *f)
3336 {
3337
3338 MOUSE_HL_INFO (f)->mouse_face_defer = false;
3339 }
3340
3341 static void
3342 pgtk_frame_up_to_date (struct frame *f)
3343 {
3344 block_input ();
3345 FRAME_MOUSE_UPDATE (f);
3346 if (!buffer_flipping_blocked_p ())
3347 {
3348 flip_cr_context (f);
3349 gtk_widget_queue_draw (FRAME_GTK_WIDGET (f));
3350 }
3351 unblock_input ();
3352 }
3353
3354
3355
3356
3357
3358
3359
3360
3361
3362
3363
3364
3365
3366
3367
3368
3369
3370
3371
3372
3373
3374 static void
3375 pgtk_mouse_position (struct frame **fp, int insist, Lisp_Object * bar_window,
3376 enum scroll_bar_part *part, Lisp_Object *x,
3377 Lisp_Object *y, Time *timestamp)
3378 {
3379 struct frame *f1;
3380 struct pgtk_display_info *dpyinfo = FRAME_DISPLAY_INFO (*fp);
3381 int win_x, win_y;
3382 GdkSeat *seat;
3383 GdkDevice *device;
3384 GdkModifierType mask;
3385 GdkWindow *win;
3386 bool return_frame_flag = false;
3387
3388 block_input ();
3389
3390 Lisp_Object frame, tail;
3391
3392
3393 FOR_EACH_FRAME (tail, frame)
3394 if (FRAME_PGTK_P (XFRAME (frame))
3395 && FRAME_X_DISPLAY (XFRAME (frame)) == FRAME_X_DISPLAY (*fp))
3396 XFRAME (frame)->mouse_moved = false;
3397
3398 dpyinfo->last_mouse_scroll_bar = NULL;
3399
3400 if (gui_mouse_grabbed (dpyinfo)
3401 && (!EQ (track_mouse, Qdropping)
3402 && !EQ (track_mouse, Qdrag_source)))
3403 f1 = dpyinfo->last_mouse_frame;
3404 else
3405 {
3406 f1 = *fp;
3407 win = gtk_widget_get_window (FRAME_GTK_WIDGET (*fp));
3408 seat = gdk_display_get_default_seat (dpyinfo->gdpy);
3409 device = gdk_seat_get_pointer (seat);
3410 win = gdk_window_get_device_position (win, device, &win_x,
3411 &win_y, &mask);
3412 if (win != NULL)
3413 f1 = pgtk_any_window_to_frame (win);
3414 else
3415 {
3416 f1 = SELECTED_FRAME ();
3417
3418 if (!FRAME_PGTK_P (f1))
3419 f1 = dpyinfo->last_mouse_frame;
3420
3421 return_frame_flag = EQ (track_mouse, Qdrag_source);
3422 }
3423 }
3424
3425
3426 if (f1 == NULL || !FRAME_PGTK_P (f1))
3427 {
3428 unblock_input ();
3429 return;
3430 }
3431
3432 win = gtk_widget_get_window (FRAME_GTK_WIDGET (f1));
3433 seat = gdk_display_get_default_seat (dpyinfo->gdpy);
3434 device = gdk_seat_get_pointer (seat);
3435
3436 win = gdk_window_get_device_position (win, device,
3437 &win_x, &win_y, &mask);
3438
3439 if (f1 != NULL)
3440 {
3441 remember_mouse_glyph (f1, win_x, win_y,
3442 &dpyinfo->last_mouse_glyph);
3443 dpyinfo->last_mouse_glyph_frame = f1;
3444
3445 *bar_window = Qnil;
3446 *part = 0;
3447 *fp = !return_frame_flag ? f1 : NULL;
3448 XSETINT (*x, win_x);
3449 XSETINT (*y, win_y);
3450 *timestamp = dpyinfo->last_mouse_movement_time;
3451 }
3452
3453 unblock_input ();
3454 }
3455
3456
3457
3458 static int max_fringe_bmp = 0;
3459 static cairo_pattern_t **fringe_bmp = 0;
3460
3461 static void
3462 pgtk_define_fringe_bitmap (int which, unsigned short *bits, int h, int wd)
3463 {
3464 int i, stride;
3465 cairo_surface_t *surface;
3466 unsigned char *data;
3467 cairo_pattern_t *pattern;
3468
3469 if (which >= max_fringe_bmp)
3470 {
3471 i = max_fringe_bmp;
3472 max_fringe_bmp = which + 20;
3473 fringe_bmp
3474 = (cairo_pattern_t **) xrealloc (fringe_bmp,
3475 max_fringe_bmp *
3476 sizeof (cairo_pattern_t *));
3477 while (i < max_fringe_bmp)
3478 fringe_bmp[i++] = 0;
3479 }
3480
3481 block_input ();
3482
3483 surface = cairo_image_surface_create (CAIRO_FORMAT_A1, wd, h);
3484 stride = cairo_image_surface_get_stride (surface);
3485 data = cairo_image_surface_get_data (surface);
3486
3487 for (i = 0; i < h; i++)
3488 {
3489 *((unsigned short *) data) = bits[i];
3490 data += stride;
3491 }
3492
3493 cairo_surface_mark_dirty (surface);
3494 pattern = cairo_pattern_create_for_surface (surface);
3495 cairo_surface_destroy (surface);
3496
3497 unblock_input ();
3498
3499 fringe_bmp[which] = pattern;
3500 }
3501
3502 static void
3503 pgtk_destroy_fringe_bitmap (int which)
3504 {
3505 if (which >= max_fringe_bmp)
3506 return;
3507
3508 if (fringe_bmp[which])
3509 {
3510 block_input ();
3511 cairo_pattern_destroy (fringe_bmp[which]);
3512 unblock_input ();
3513 }
3514 fringe_bmp[which] = 0;
3515 }
3516
3517 static void
3518 pgtk_clip_to_row (struct window *w, struct glyph_row *row,
3519 enum glyph_row_area area, cairo_t * cr)
3520 {
3521 int window_x, window_y, window_width;
3522 cairo_rectangle_int_t rect;
3523
3524 window_box (w, area, &window_x, &window_y, &window_width, 0);
3525
3526 rect.x = window_x;
3527 rect.y = WINDOW_TO_FRAME_PIXEL_Y (w, max (0, row->y));
3528 rect.y = max (rect.y, window_y);
3529 rect.width = window_width;
3530 rect.height = row->visible_height;
3531
3532 cairo_rectangle (cr, rect.x, rect.y, rect.width, rect.height);
3533 cairo_clip (cr);
3534 }
3535
3536 static void
3537 pgtk_draw_fringe_bitmap (struct window *w, struct glyph_row *row,
3538 struct draw_fringe_bitmap_params *p)
3539 {
3540 struct frame *f = XFRAME (WINDOW_FRAME (w));
3541 struct face *face = p->face;
3542
3543 cairo_t *cr = pgtk_begin_cr_clip (f);
3544
3545
3546 pgtk_clip_to_row (w, row, ANY_AREA, cr);
3547
3548 if (p->bx >= 0 && !p->overlay_p)
3549 {
3550
3551
3552
3553
3554 if (face->stipple)
3555 fill_background_by_face (f, face, p->bx, p->by, p->nx, p->ny);
3556 else
3557 {
3558 pgtk_set_cr_source_with_color (f, face->background, true);
3559 cairo_rectangle (cr, p->bx, p->by, p->nx, p->ny);
3560 cairo_fill (cr);
3561 }
3562 }
3563
3564 if (p->which
3565 && p->which < max_fringe_bmp
3566 && p->which < max_used_fringe_bitmap)
3567 {
3568 Emacs_GC gcv;
3569
3570 if (!fringe_bmp[p->which])
3571 {
3572
3573
3574
3575
3576
3577
3578 gui_define_fringe_bitmap (f, p->which);
3579 }
3580
3581 gcv.foreground = (p->cursor_p
3582 ? (p->overlay_p ? face->background
3583 : FRAME_X_OUTPUT (f)->cursor_color)
3584 : face->foreground);
3585 gcv.background = face->background;
3586 pgtk_cr_draw_image (f, &gcv, fringe_bmp[p->which], 0, p->dh,
3587 p->wd, p->h, p->x, p->y, p->overlay_p);
3588 }
3589
3590 pgtk_end_cr_clip (f);
3591 }
3592
3593 static struct atimer *hourglass_atimer = NULL;
3594 static int hourglass_enter_count = 0;
3595
3596 static void
3597 hourglass_cb (struct atimer *timer)
3598 {
3599
3600 }
3601
3602 static void
3603 pgtk_show_hourglass (struct frame *f)
3604 {
3605 struct pgtk_output *x = FRAME_X_OUTPUT (f);
3606 if (x->hourglass_widget != NULL)
3607 gtk_widget_destroy (x->hourglass_widget);
3608
3609
3610 x->hourglass_widget = gtk_event_box_new ();
3611 gtk_widget_set_has_window (x->hourglass_widget, true);
3612 gtk_fixed_put (GTK_FIXED (FRAME_GTK_WIDGET (f)), x->hourglass_widget, 0, 0);
3613 gtk_widget_show (x->hourglass_widget);
3614 gtk_widget_set_size_request (x->hourglass_widget, 30000, 30000);
3615 gdk_window_raise (gtk_widget_get_window (x->hourglass_widget));
3616 gdk_window_set_cursor (gtk_widget_get_window (x->hourglass_widget),
3617 x->hourglass_cursor);
3618
3619
3620
3621 if (hourglass_enter_count++ == 0)
3622 {
3623 struct timespec ts = make_timespec (0, 50 * 1000 * 1000);
3624 if (hourglass_atimer != NULL)
3625 cancel_atimer (hourglass_atimer);
3626 hourglass_atimer
3627 = start_atimer (ATIMER_CONTINUOUS, ts, hourglass_cb, NULL);
3628 }
3629 }
3630
3631 static void
3632 pgtk_hide_hourglass (struct frame *f)
3633 {
3634 struct pgtk_output *x = FRAME_X_OUTPUT (f);
3635 if (--hourglass_enter_count == 0)
3636 {
3637 if (hourglass_atimer != NULL)
3638 {
3639 cancel_atimer (hourglass_atimer);
3640 hourglass_atimer = NULL;
3641 }
3642 }
3643 if (x->hourglass_widget != NULL)
3644 {
3645 gtk_widget_destroy (x->hourglass_widget);
3646 x->hourglass_widget = NULL;
3647 }
3648 }
3649
3650
3651 static void
3652 pgtk_flush_display (struct frame *f)
3653 {
3654 }
3655
3656 extern frame_parm_handler pgtk_frame_parm_handlers[];
3657
3658 static struct redisplay_interface pgtk_redisplay_interface = {
3659 pgtk_frame_parm_handlers,
3660 gui_produce_glyphs,
3661 gui_write_glyphs,
3662 gui_insert_glyphs,
3663 gui_clear_end_of_line,
3664 pgtk_scroll_run,
3665 pgtk_after_update_window_line,
3666 NULL,
3667 NULL,
3668 pgtk_flush_display,
3669 gui_clear_window_mouse_face,
3670 gui_get_glyph_overhangs,
3671 gui_fix_overlapping_area,
3672 pgtk_draw_fringe_bitmap,
3673 pgtk_define_fringe_bitmap,
3674 pgtk_destroy_fringe_bitmap,
3675 pgtk_compute_glyph_string_overhangs,
3676 pgtk_draw_glyph_string,
3677 pgtk_define_frame_cursor,
3678 pgtk_clear_frame_area,
3679 pgtk_clear_under_internal_border,
3680 pgtk_draw_window_cursor,
3681 pgtk_draw_vertical_window_border,
3682 pgtk_draw_window_divider,
3683 NULL,
3684 pgtk_show_hourglass,
3685 pgtk_hide_hourglass,
3686 pgtk_default_font_parameter,
3687 };
3688
3689 void
3690 pgtk_clear_frame (struct frame *f)
3691 {
3692 if (!FRAME_DEFAULT_FACE (f))
3693 return;
3694
3695 mark_window_cursors_off (XWINDOW (FRAME_ROOT_WINDOW (f)));
3696
3697 block_input ();
3698 pgtk_clear_area (f, 0, 0, FRAME_PIXEL_WIDTH (f), FRAME_PIXEL_HEIGHT (f));
3699 unblock_input ();
3700 }
3701
3702 static void
3703 recover_from_visible_bell (struct atimer *timer)
3704 {
3705 struct frame *f = timer->client_data;
3706
3707 if (FRAME_X_OUTPUT (f)->cr_surface_visible_bell != NULL)
3708 {
3709 cairo_surface_destroy (FRAME_X_OUTPUT (f)->cr_surface_visible_bell);
3710 FRAME_X_OUTPUT (f)->cr_surface_visible_bell = NULL;
3711 }
3712
3713 if (FRAME_X_OUTPUT (f)->atimer_visible_bell != NULL)
3714 FRAME_X_OUTPUT (f)->atimer_visible_bell = NULL;
3715 }
3716
3717
3718
3719 static void
3720 pgtk_flash (struct frame *f)
3721 {
3722 cairo_surface_t *surface_orig, *surface;
3723 cairo_t *cr;
3724 int width, height, flash_height, flash_left, flash_right;
3725 struct timespec delay;
3726
3727 if (!FRAME_CR_CONTEXT (f))
3728 return;
3729
3730 block_input ();
3731
3732 surface_orig = FRAME_CR_SURFACE (f);
3733
3734 width = FRAME_CR_SURFACE_DESIRED_WIDTH (f);
3735 height = FRAME_CR_SURFACE_DESIRED_HEIGHT (f);
3736 surface = cairo_surface_create_similar (surface_orig,
3737 CAIRO_CONTENT_COLOR_ALPHA,
3738 width, height);
3739
3740 cr = cairo_create (surface);
3741 cairo_set_source_surface (cr, surface_orig, 0, 0);
3742 cairo_rectangle (cr, 0, 0, width, height);
3743 cairo_clip (cr);
3744 cairo_paint (cr);
3745
3746 cairo_set_source_rgb (cr, 1, 1, 1);
3747 cairo_set_operator (cr, CAIRO_OPERATOR_DIFFERENCE);
3748
3749
3750 height = FRAME_PIXEL_HEIGHT (f);
3751
3752 flash_height = FRAME_LINE_HEIGHT (f);
3753
3754 flash_left = FRAME_INTERNAL_BORDER_WIDTH (f);
3755 flash_right = (FRAME_PIXEL_WIDTH (f)
3756 - FRAME_INTERNAL_BORDER_WIDTH (f));
3757 width = flash_right - flash_left;
3758
3759
3760 if (height > 3 * FRAME_LINE_HEIGHT (f))
3761 {
3762 cairo_rectangle (cr,
3763 flash_left,
3764 (FRAME_INTERNAL_BORDER_WIDTH (f)
3765 + FRAME_TOP_MARGIN_HEIGHT (f)),
3766 width, flash_height);
3767 cairo_fill (cr);
3768
3769 cairo_rectangle (cr,
3770 flash_left,
3771 (height - flash_height
3772 - FRAME_INTERNAL_BORDER_WIDTH (f)),
3773 width, flash_height);
3774 cairo_fill (cr);
3775 }
3776 else
3777 {
3778
3779 cairo_rectangle (cr,
3780 flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
3781 width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
3782 cairo_fill (cr);
3783 }
3784
3785 FRAME_X_OUTPUT (f)->cr_surface_visible_bell = surface;
3786
3787 delay = make_timespec (0, 50 * 1000 * 1000);
3788
3789 if (FRAME_X_OUTPUT (f)->atimer_visible_bell != NULL)
3790 {
3791 cancel_atimer (FRAME_X_OUTPUT (f)->atimer_visible_bell);
3792 FRAME_X_OUTPUT (f)->atimer_visible_bell = NULL;
3793 }
3794
3795 FRAME_X_OUTPUT (f)->atimer_visible_bell
3796 = start_atimer (ATIMER_RELATIVE, delay, recover_from_visible_bell, f);
3797
3798
3799 cairo_destroy (cr);
3800 unblock_input ();
3801 }
3802
3803
3804
3805 static void
3806 pgtk_ring_bell (struct frame *f)
3807 {
3808 if (visible_bell)
3809 {
3810 pgtk_flash (f);
3811 }
3812 else
3813 {
3814 block_input ();
3815 gtk_widget_error_bell (FRAME_GTK_WIDGET (f));
3816 unblock_input ();
3817 }
3818 }
3819
3820
3821
3822
3823
3824
3825
3826
3827
3828 static int
3829 pgtk_read_socket (struct terminal *terminal, struct input_event *hold_quit)
3830 {
3831 GMainContext *context;
3832 bool context_acquired = false;
3833 int count;
3834
3835 count = evq_flush (hold_quit);
3836 if (count > 0)
3837 {
3838 return count;
3839 }
3840
3841 context = g_main_context_default ();
3842 context_acquired = g_main_context_acquire (context);
3843
3844 block_input ();
3845
3846 if (context_acquired)
3847 {
3848 while (g_main_context_pending (context))
3849 {
3850 g_main_context_dispatch (context);
3851 }
3852 }
3853
3854 unblock_input ();
3855
3856 if (context_acquired)
3857 g_main_context_release (context);
3858
3859 count = evq_flush (hold_quit);
3860 if (count > 0)
3861 {
3862 return count;
3863 }
3864
3865 return 0;
3866 }
3867
3868
3869
3870
3871 static Lisp_Object window_being_scrolled;
3872
3873 static void
3874 pgtk_send_scroll_bar_event (Lisp_Object window, enum scroll_bar_part part,
3875 int portion, int whole, bool horizontal)
3876 {
3877 union buffered_input_event inev;
3878
3879 EVENT_INIT (inev.ie);
3880
3881 inev.ie.kind = (horizontal
3882 ? HORIZONTAL_SCROLL_BAR_CLICK_EVENT
3883 : SCROLL_BAR_CLICK_EVENT);
3884 inev.ie.frame_or_window = window;
3885 inev.ie.arg = Qnil;
3886 inev.ie.timestamp = 0;
3887 inev.ie.code = 0;
3888 inev.ie.part = part;
3889 inev.ie.x = make_fixnum (portion);
3890 inev.ie.y = make_fixnum (whole);
3891 inev.ie.modifiers = 0;
3892
3893 evq_enqueue (&inev);
3894 }
3895
3896
3897
3898
3899
3900 static gboolean
3901 xg_scroll_callback (GtkRange * range,
3902 GtkScrollType scroll, gdouble value, gpointer user_data)
3903 {
3904 int whole = 0, portion = 0;
3905 struct scroll_bar *bar = user_data;
3906 enum scroll_bar_part part = scroll_bar_nowhere;
3907 GtkAdjustment *adj = GTK_ADJUSTMENT (gtk_range_get_adjustment (range));
3908
3909 if (xg_ignore_gtk_scrollbar)
3910 return false;
3911
3912 switch (scroll)
3913 {
3914 case GTK_SCROLL_JUMP:
3915 if (bar->horizontal)
3916 {
3917 part = scroll_bar_horizontal_handle;
3918 whole = (int) (gtk_adjustment_get_upper (adj) -
3919 gtk_adjustment_get_page_size (adj));
3920 portion = min ((int) value, whole);
3921 bar->dragging = portion;
3922 }
3923 else
3924 {
3925 part = scroll_bar_handle;
3926 whole = gtk_adjustment_get_upper (adj) -
3927 gtk_adjustment_get_page_size (adj);
3928 portion = min ((int) value, whole);
3929 bar->dragging = portion;
3930 }
3931 break;
3932 case GTK_SCROLL_STEP_BACKWARD:
3933 part = (bar->horizontal ? scroll_bar_left_arrow : scroll_bar_up_arrow);
3934 bar->dragging = -1;
3935 break;
3936 case GTK_SCROLL_STEP_FORWARD:
3937 part = (bar->horizontal
3938 ? scroll_bar_right_arrow : scroll_bar_down_arrow);
3939 bar->dragging = -1;
3940 break;
3941 case GTK_SCROLL_PAGE_BACKWARD:
3942 part = (bar->horizontal
3943 ? scroll_bar_before_handle : scroll_bar_above_handle);
3944 bar->dragging = -1;
3945 break;
3946 case GTK_SCROLL_PAGE_FORWARD:
3947 part = (bar->horizontal
3948 ? scroll_bar_after_handle : scroll_bar_below_handle);
3949 bar->dragging = -1;
3950 break;
3951 default:
3952 break;
3953 }
3954
3955 if (part != scroll_bar_nowhere)
3956 {
3957 window_being_scrolled = bar->window;
3958 pgtk_send_scroll_bar_event (bar->window, part, portion, whole,
3959 bar->horizontal);
3960 }
3961
3962 return false;
3963 }
3964
3965
3966
3967 static gboolean
3968 xg_end_scroll_callback (GtkWidget * widget,
3969 GdkEventButton * event, gpointer user_data)
3970 {
3971 struct scroll_bar *bar = user_data;
3972 bar->dragging = -1;
3973 if (WINDOWP (window_being_scrolled))
3974 {
3975 pgtk_send_scroll_bar_event (window_being_scrolled,
3976 scroll_bar_end_scroll, 0, 0,
3977 bar->horizontal);
3978 window_being_scrolled = Qnil;
3979 }
3980
3981 return false;
3982 }
3983
3984 #define SCROLL_BAR_NAME "verticalScrollBar"
3985 #define SCROLL_BAR_HORIZONTAL_NAME "horizontalScrollBar"
3986
3987
3988
3989
3990 static void
3991 pgtk_create_toolkit_scroll_bar (struct frame *f, struct scroll_bar *bar)
3992 {
3993 const char *scroll_bar_name = SCROLL_BAR_NAME;
3994
3995 block_input ();
3996 xg_create_scroll_bar (f, bar, G_CALLBACK (xg_scroll_callback),
3997 G_CALLBACK (xg_end_scroll_callback), scroll_bar_name);
3998 unblock_input ();
3999 }
4000
4001 static void
4002 pgtk_create_horizontal_toolkit_scroll_bar (struct frame *f,
4003 struct scroll_bar *bar)
4004 {
4005 const char *scroll_bar_name = SCROLL_BAR_HORIZONTAL_NAME;
4006
4007 block_input ();
4008 xg_create_horizontal_scroll_bar (f, bar, G_CALLBACK (xg_scroll_callback),
4009 G_CALLBACK (xg_end_scroll_callback),
4010 scroll_bar_name);
4011 unblock_input ();
4012 }
4013
4014
4015
4016
4017 static void
4018 pgtk_set_toolkit_scroll_bar_thumb (struct scroll_bar *bar, int portion,
4019 int position, int whole)
4020 {
4021 xg_set_toolkit_scroll_bar_thumb (bar, portion, position, whole);
4022 }
4023
4024 static void
4025 pgtk_set_toolkit_horizontal_scroll_bar_thumb (struct scroll_bar *bar,
4026 int portion, int position,
4027 int whole)
4028 {
4029 xg_set_toolkit_horizontal_scroll_bar_thumb (bar, portion, position, whole);
4030 }
4031
4032
4033
4034
4035
4036
4037 static struct scroll_bar *
4038 pgtk_scroll_bar_create (struct window *w, int top, int left,
4039 int width, int height, bool horizontal)
4040 {
4041 struct frame *f = XFRAME (w->frame);
4042 struct scroll_bar *bar
4043 = ALLOCATE_PSEUDOVECTOR (struct scroll_bar, prev, PVEC_OTHER);
4044 Lisp_Object barobj;
4045
4046 block_input ();
4047
4048 if (horizontal)
4049 pgtk_create_horizontal_toolkit_scroll_bar (f, bar);
4050 else
4051 pgtk_create_toolkit_scroll_bar (f, bar);
4052
4053 XSETWINDOW (bar->window, w);
4054 bar->top = top;
4055 bar->left = left;
4056 bar->width = width;
4057 bar->height = height;
4058 bar->start = 0;
4059 bar->end = 0;
4060 bar->dragging = -1;
4061 bar->horizontal = horizontal;
4062
4063
4064 bar->next = FRAME_SCROLL_BARS (f);
4065 bar->prev = Qnil;
4066 XSETVECTOR (barobj, bar);
4067 fset_scroll_bars (f, barobj);
4068 if (!NILP (bar->next))
4069 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
4070
4071
4072 {
4073 if (horizontal)
4074 xg_update_horizontal_scrollbar_pos (f, bar->x_window, top,
4075 left, width, max (height, 1));
4076 else
4077 xg_update_scrollbar_pos (f, bar->x_window, top,
4078 left, width, max (height, 1));
4079 }
4080
4081 unblock_input ();
4082 return bar;
4083 }
4084
4085
4086
4087
4088 static void
4089 pgtk_scroll_bar_remove (struct scroll_bar *bar)
4090 {
4091 struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
4092 block_input ();
4093
4094 xg_remove_scroll_bar (f, bar->x_window);
4095
4096
4097 if (bar->horizontal)
4098 wset_horizontal_scroll_bar (XWINDOW (bar->window), Qnil);
4099 else
4100 wset_vertical_scroll_bar (XWINDOW (bar->window), Qnil);
4101
4102 unblock_input ();
4103 }
4104
4105
4106
4107
4108
4109
4110 static void
4111 pgtk_set_vertical_scroll_bar (struct window *w, int portion, int whole,
4112 int position)
4113 {
4114 struct frame *f = XFRAME (w->frame);
4115 Lisp_Object barobj;
4116 struct scroll_bar *bar;
4117 int top, height, left, width;
4118 int window_y, window_height;
4119
4120
4121 window_box (w, ANY_AREA, 0, &window_y, 0, &window_height);
4122 top = window_y;
4123 height = window_height;
4124 left = WINDOW_SCROLL_BAR_AREA_X (w);
4125 width = WINDOW_SCROLL_BAR_AREA_WIDTH (w);
4126
4127
4128 if (NILP (w->vertical_scroll_bar))
4129 {
4130 if (width > 0 && height > 0)
4131 {
4132 block_input ();
4133 pgtk_clear_area (f, left, top, width, height);
4134 unblock_input ();
4135 }
4136
4137 bar = pgtk_scroll_bar_create (w, top, left, width, max (height, 1), false);
4138 }
4139 else
4140 {
4141
4142 unsigned int mask = 0;
4143
4144 bar = XSCROLL_BAR (w->vertical_scroll_bar);
4145
4146 block_input ();
4147
4148 if (left != bar->left)
4149 mask |= 1;
4150 if (top != bar->top)
4151 mask |= 1;
4152 if (width != bar->width)
4153 mask |= 1;
4154 if (height != bar->height)
4155 mask |= 1;
4156
4157
4158 if (mask)
4159 {
4160
4161
4162 if (width > 0 && height > 0)
4163 pgtk_clear_area (f, left, top, width, height);
4164 xg_update_scrollbar_pos (f, bar->x_window, top,
4165 left, width, max (height, 1));
4166 }
4167
4168
4169 bar->left = left;
4170 bar->top = top;
4171 bar->width = width;
4172 bar->height = height;
4173
4174 unblock_input ();
4175 }
4176
4177 pgtk_set_toolkit_scroll_bar_thumb (bar, portion, position, whole);
4178
4179 XSETVECTOR (barobj, bar);
4180 wset_vertical_scroll_bar (w, barobj);
4181 }
4182
4183 static void
4184 pgtk_set_horizontal_scroll_bar (struct window *w, int portion, int whole,
4185 int position)
4186 {
4187 struct frame *f = XFRAME (w->frame);
4188 Lisp_Object barobj;
4189 struct scroll_bar *bar;
4190 int top, height, left, width;
4191 int window_x, window_width;
4192 int pixel_width = WINDOW_PIXEL_WIDTH (w);
4193
4194
4195 window_box (w, ANY_AREA, &window_x, 0, &window_width, 0);
4196 left = window_x;
4197 width = window_width;
4198 top = WINDOW_SCROLL_BAR_AREA_Y (w);
4199 height = WINDOW_SCROLL_BAR_AREA_HEIGHT (w);
4200
4201
4202 if (NILP (w->horizontal_scroll_bar))
4203 {
4204 if (width > 0 && height > 0)
4205 {
4206 block_input ();
4207
4208
4209
4210 pgtk_clear_area (f, left, top, pixel_width, height);
4211 unblock_input ();
4212 }
4213
4214 bar = pgtk_scroll_bar_create (w, top, left, width, height, true);
4215 }
4216 else
4217 {
4218
4219 unsigned int mask = 0;
4220
4221 bar = XSCROLL_BAR (w->horizontal_scroll_bar);
4222
4223 block_input ();
4224
4225 if (left != bar->left)
4226 mask |= 1;
4227 if (top != bar->top)
4228 mask |= 1;
4229 if (width != bar->width)
4230 mask |= 1;
4231 if (height != bar->height)
4232 mask |= 1;
4233
4234
4235 if (mask)
4236 {
4237
4238
4239 if (width > 0 && height > 0)
4240 pgtk_clear_area (f,
4241 WINDOW_LEFT_EDGE_X (w), top,
4242 pixel_width - WINDOW_RIGHT_DIVIDER_WIDTH (w),
4243 height);
4244 xg_update_horizontal_scrollbar_pos (f, bar->x_window, top, left,
4245 width, height);
4246 }
4247
4248
4249 bar->left = left;
4250 bar->top = top;
4251 bar->width = width;
4252 bar->height = height;
4253
4254 unblock_input ();
4255 }
4256
4257 pgtk_set_toolkit_horizontal_scroll_bar_thumb (bar, portion, position, whole);
4258
4259 XSETVECTOR (barobj, bar);
4260 wset_horizontal_scroll_bar (w, barobj);
4261 }
4262
4263
4264
4265
4266
4267
4268
4269
4270
4271
4272
4273
4274
4275 static void
4276 pgtk_condemn_scroll_bars (struct frame *frame)
4277 {
4278 if (!NILP (FRAME_SCROLL_BARS (frame)))
4279 {
4280 if (!NILP (FRAME_CONDEMNED_SCROLL_BARS (frame)))
4281 {
4282
4283 Lisp_Object last = FRAME_SCROLL_BARS (frame);
4284
4285 while (!NILP (XSCROLL_BAR (last)->next))
4286 last = XSCROLL_BAR (last)->next;
4287
4288 XSCROLL_BAR (last)->next = FRAME_CONDEMNED_SCROLL_BARS (frame);
4289 XSCROLL_BAR (FRAME_CONDEMNED_SCROLL_BARS (frame))->prev = last;
4290 }
4291
4292 fset_condemned_scroll_bars (frame, FRAME_SCROLL_BARS (frame));
4293 fset_scroll_bars (frame, Qnil);
4294 }
4295 }
4296
4297
4298
4299
4300 static void
4301 pgtk_redeem_scroll_bar (struct window *w)
4302 {
4303 struct scroll_bar *bar;
4304 Lisp_Object barobj;
4305 struct frame *f;
4306
4307
4308 if (NILP (w->vertical_scroll_bar) && NILP (w->horizontal_scroll_bar))
4309 emacs_abort ();
4310
4311 if (!NILP (w->vertical_scroll_bar) && WINDOW_HAS_VERTICAL_SCROLL_BAR (w))
4312 {
4313 bar = XSCROLL_BAR (w->vertical_scroll_bar);
4314
4315 f = XFRAME (WINDOW_FRAME (w));
4316 if (NILP (bar->prev))
4317 {
4318
4319
4320 if (EQ (FRAME_SCROLL_BARS (f), w->vertical_scroll_bar))
4321
4322 goto horizontal;
4323 else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f),
4324 w->vertical_scroll_bar))
4325 fset_condemned_scroll_bars (f, bar->next);
4326 else
4327
4328
4329 emacs_abort ();
4330 }
4331 else
4332 XSCROLL_BAR (bar->prev)->next = bar->next;
4333
4334 if (!NILP (bar->next))
4335 XSCROLL_BAR (bar->next)->prev = bar->prev;
4336
4337 bar->next = FRAME_SCROLL_BARS (f);
4338 bar->prev = Qnil;
4339 XSETVECTOR (barobj, bar);
4340 fset_scroll_bars (f, barobj);
4341 if (!NILP (bar->next))
4342 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
4343 }
4344
4345 horizontal:
4346 if (!NILP (w->horizontal_scroll_bar)
4347 && WINDOW_HAS_HORIZONTAL_SCROLL_BAR (w))
4348 {
4349 bar = XSCROLL_BAR (w->horizontal_scroll_bar);
4350
4351 f = XFRAME (WINDOW_FRAME (w));
4352 if (NILP (bar->prev))
4353 {
4354
4355
4356 if (EQ (FRAME_SCROLL_BARS (f), w->horizontal_scroll_bar))
4357
4358 return;
4359 else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f),
4360 w->horizontal_scroll_bar))
4361 fset_condemned_scroll_bars (f, bar->next);
4362 else
4363
4364
4365 emacs_abort ();
4366 }
4367 else
4368 XSCROLL_BAR (bar->prev)->next = bar->next;
4369
4370 if (!NILP (bar->next))
4371 XSCROLL_BAR (bar->next)->prev = bar->prev;
4372
4373 bar->next = FRAME_SCROLL_BARS (f);
4374 bar->prev = Qnil;
4375 XSETVECTOR (barobj, bar);
4376 fset_scroll_bars (f, barobj);
4377 if (!NILP (bar->next))
4378 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
4379 }
4380 }
4381
4382
4383
4384
4385 static void
4386 pgtk_judge_scroll_bars (struct frame *f)
4387 {
4388 Lisp_Object bar, next;
4389
4390 bar = FRAME_CONDEMNED_SCROLL_BARS (f);
4391
4392
4393
4394 fset_condemned_scroll_bars (f, Qnil);
4395
4396 for (; !NILP (bar); bar = next)
4397 {
4398 struct scroll_bar *b = XSCROLL_BAR (bar);
4399
4400 pgtk_scroll_bar_remove (b);
4401
4402 next = b->next;
4403 b->next = b->prev = Qnil;
4404 }
4405
4406
4407
4408 }
4409
4410 static void
4411 set_fullscreen_state (struct frame *f)
4412 {
4413 if (!FRAME_GTK_OUTER_WIDGET (f))
4414 return;
4415
4416 GtkWindow *widget = GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f));
4417 switch (f->want_fullscreen)
4418 {
4419 case FULLSCREEN_NONE:
4420 gtk_window_unfullscreen (widget);
4421 gtk_window_unmaximize (widget);
4422 store_frame_param (f, Qfullscreen, Qnil);
4423 break;
4424
4425 case FULLSCREEN_BOTH:
4426 gtk_window_unmaximize (widget);
4427 gtk_window_fullscreen (widget);
4428 store_frame_param (f, Qfullscreen, Qfullboth);
4429 break;
4430
4431 case FULLSCREEN_MAXIMIZED:
4432 gtk_window_unfullscreen (widget);
4433 gtk_window_maximize (widget);
4434 store_frame_param (f, Qfullscreen, Qmaximized);
4435 break;
4436
4437 case FULLSCREEN_WIDTH:
4438 case FULLSCREEN_HEIGHT:
4439
4440 break;
4441 }
4442
4443 f->want_fullscreen = FULLSCREEN_NONE;
4444 }
4445
4446 static void
4447 pgtk_fullscreen_hook (struct frame *f)
4448 {
4449 if (FRAME_VISIBLE_P (f))
4450 {
4451 block_input ();
4452 set_fullscreen_state (f);
4453 unblock_input ();
4454 }
4455 }
4456
4457
4458 void
4459 pgtk_delete_terminal (struct terminal *terminal)
4460 {
4461 struct pgtk_display_info *dpyinfo = terminal->display_info.pgtk;
4462
4463
4464
4465 if (!terminal->name)
4466 return;
4467
4468 block_input ();
4469
4470 pgtk_im_finish (dpyinfo);
4471
4472
4473 if (dpyinfo->gdpy)
4474 {
4475 image_destroy_all_bitmaps (dpyinfo);
4476
4477 g_clear_object (&dpyinfo->xg_cursor);
4478 g_clear_object (&dpyinfo->vertical_scroll_bar_cursor);
4479 g_clear_object (&dpyinfo->horizontal_scroll_bar_cursor);
4480 g_clear_object (&dpyinfo->invisible_cursor);
4481 if (dpyinfo->last_click_event != NULL)
4482 {
4483 gdk_event_free (dpyinfo->last_click_event);
4484 dpyinfo->last_click_event = NULL;
4485 }
4486
4487
4488
4489 g_signal_handlers_disconnect_by_func (G_OBJECT (dpyinfo->gdpy),
4490 G_CALLBACK (pgtk_seat_added_cb),
4491 dpyinfo);
4492 g_signal_handlers_disconnect_by_func (G_OBJECT (dpyinfo->gdpy),
4493 G_CALLBACK (pgtk_seat_removed_cb),
4494 dpyinfo);
4495 xg_display_close (dpyinfo->gdpy);
4496
4497 dpyinfo->gdpy = NULL;
4498 }
4499
4500 if (dpyinfo->connection >= 0)
4501 emacs_close (dpyinfo->connection);
4502
4503 dpyinfo->connection = -1;
4504
4505 delete_keyboard_wait_descriptor (0);
4506
4507 pgtk_delete_display (dpyinfo);
4508 unblock_input ();
4509 }
4510
4511
4512 static void
4513 pgtk_query_frame_background_color (struct frame *f, Emacs_Color * bgcolor)
4514 {
4515 bgcolor->pixel = FRAME_BACKGROUND_PIXEL (f);
4516 pgtk_query_color (f, bgcolor);
4517 }
4518
4519 static void
4520 pgtk_free_pixmap (struct frame *f, Emacs_Pixmap pixmap)
4521 {
4522 if (pixmap)
4523 {
4524 xfree (pixmap->data);
4525 xfree (pixmap);
4526 }
4527 }
4528
4529 void
4530 pgtk_focus_frame (struct frame *f, bool noactivate)
4531 {
4532 struct pgtk_display_info *dpyinfo;
4533 GtkWidget *widget;
4534 GtkWindow *window;
4535
4536 dpyinfo = FRAME_DISPLAY_INFO (f);
4537
4538 if (FRAME_GTK_OUTER_WIDGET (f) && !noactivate)
4539 {
4540
4541
4542
4543
4544
4545
4546 window = GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f));
4547 gtk_window_present_with_time (window, dpyinfo->last_user_time);
4548 return;
4549 }
4550
4551 widget = FRAME_WIDGET (f);
4552
4553 if (widget)
4554 gtk_widget_grab_focus (widget);
4555 }
4556
4557 static void
4558 set_opacity_recursively (GtkWidget *w, gpointer data)
4559 {
4560 gtk_widget_set_opacity (w, *(double *) data);
4561
4562 if (GTK_IS_CONTAINER (w))
4563 gtk_container_foreach (GTK_CONTAINER (w),
4564 set_opacity_recursively, data);
4565 }
4566
4567 static void
4568 pgtk_set_frame_alpha (struct frame *f)
4569 {
4570 struct pgtk_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
4571 double alpha = 1.0;
4572 double alpha_min = 1.0;
4573
4574 if (dpyinfo->highlight_frame == f)
4575 alpha = f->alpha[0];
4576 else
4577 alpha = f->alpha[1];
4578
4579 if (alpha < 0.0)
4580 return;
4581
4582 if (FLOATP (Vframe_alpha_lower_limit))
4583 alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
4584 else if (FIXNUMP (Vframe_alpha_lower_limit))
4585 alpha_min = (XFIXNUM (Vframe_alpha_lower_limit)) / 100.0;
4586
4587 if (alpha > 1.0)
4588 alpha = 1.0;
4589 else if (alpha < alpha_min && alpha_min <= 1.0)
4590 alpha = alpha_min;
4591
4592 set_opacity_recursively (FRAME_WIDGET (f), &alpha);
4593
4594 gtk_widget_queue_resize_no_redraw (FRAME_WIDGET (f));
4595 }
4596
4597 static void
4598 frame_highlight (struct frame *f)
4599 {
4600 block_input ();
4601 GtkWidget *w = FRAME_WIDGET (f);
4602
4603 char *css = g_strdup_printf ("decoration { border: solid %dpx #%06x; }",
4604 f->border_width,
4605 ((unsigned int) FRAME_X_OUTPUT (f)->border_pixel
4606 & 0x00ffffff));
4607
4608 GtkStyleContext *ctxt = gtk_widget_get_style_context (w);
4609 GtkCssProvider *css_provider = gtk_css_provider_new ();
4610 gtk_css_provider_load_from_data (css_provider, css, -1, NULL);
4611 gtk_style_context_add_provider (ctxt, GTK_STYLE_PROVIDER (css_provider),
4612 GTK_STYLE_PROVIDER_PRIORITY_USER);
4613 g_free (css);
4614
4615 GtkCssProvider *old = FRAME_X_OUTPUT (f)->border_color_css_provider;
4616 FRAME_X_OUTPUT (f)->border_color_css_provider = css_provider;
4617 if (old != NULL)
4618 {
4619 gtk_style_context_remove_provider (ctxt, GTK_STYLE_PROVIDER (old));
4620 g_object_unref (old);
4621 }
4622
4623 unblock_input ();
4624 gui_update_cursor (f, true);
4625 pgtk_set_frame_alpha (f);
4626 }
4627
4628 static void
4629 frame_unhighlight (struct frame *f)
4630 {
4631 GtkWidget *w;
4632 char *css;
4633 GtkStyleContext *ctxt;
4634 GtkCssProvider *css_provider, *old;
4635
4636 block_input ();
4637
4638 w = FRAME_WIDGET (f);
4639
4640 css = g_strdup_printf ("decoration { border: dotted %dpx #ffffff; }",
4641 f->border_width);
4642
4643 ctxt = gtk_widget_get_style_context (w);
4644 css_provider = gtk_css_provider_new ();
4645 gtk_css_provider_load_from_data (css_provider, css, -1, NULL);
4646 gtk_style_context_add_provider (ctxt, GTK_STYLE_PROVIDER (css_provider),
4647 GTK_STYLE_PROVIDER_PRIORITY_USER);
4648 g_free (css);
4649
4650 old = FRAME_X_OUTPUT (f)->border_color_css_provider;
4651 FRAME_X_OUTPUT (f)->border_color_css_provider = css_provider;
4652 if (old != NULL)
4653 {
4654 gtk_style_context_remove_provider (ctxt, GTK_STYLE_PROVIDER (old));
4655 g_object_unref (old);
4656 }
4657
4658 unblock_input ();
4659 gui_update_cursor (f, true);
4660 pgtk_set_frame_alpha (f);
4661 }
4662
4663
4664 void
4665 pgtk_frame_rehighlight (struct pgtk_display_info *dpyinfo)
4666 {
4667 struct frame *old_highlight = dpyinfo->highlight_frame;
4668
4669 if (dpyinfo->x_focus_frame)
4670 {
4671 dpyinfo->highlight_frame
4672 = ((FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame)))
4673 ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
4674 : dpyinfo->x_focus_frame);
4675 if (!FRAME_LIVE_P (dpyinfo->highlight_frame))
4676 {
4677 fset_focus_frame (dpyinfo->x_focus_frame, Qnil);
4678 dpyinfo->highlight_frame = dpyinfo->x_focus_frame;
4679 }
4680 }
4681 else
4682 dpyinfo->highlight_frame = 0;
4683
4684 if (old_highlight)
4685 frame_unhighlight (old_highlight);
4686 if (dpyinfo->highlight_frame)
4687 frame_highlight (dpyinfo->highlight_frame);
4688 }
4689
4690
4691
4692
4693
4694
4695
4696
4697
4698 static void
4699 pgtk_frame_rehighlight_hook (struct frame *frame)
4700 {
4701 pgtk_frame_rehighlight (FRAME_DISPLAY_INFO (frame));
4702 }
4703
4704
4705
4706 static void
4707 pgtk_toggle_invisible_pointer (struct frame *f, bool invisible)
4708 {
4709 Emacs_Cursor cursor;
4710 if (invisible)
4711 cursor = FRAME_DISPLAY_INFO (f)->invisible_cursor;
4712 else
4713 cursor = f->output_data.pgtk->current_cursor;
4714 gdk_window_set_cursor (gtk_widget_get_window (FRAME_GTK_WIDGET (f)),
4715 cursor);
4716 f->pointer_invisible = invisible;
4717
4718
4719
4720 gdk_display_flush (FRAME_X_DISPLAY (f));
4721 }
4722
4723
4724
4725
4726
4727
4728
4729 static void
4730 pgtk_new_focus_frame (struct pgtk_display_info *dpyinfo, struct frame *frame)
4731 {
4732 struct frame *old_focus = dpyinfo->x_focus_frame;
4733
4734
4735 if (frame != dpyinfo->x_focus_frame)
4736 {
4737
4738
4739 dpyinfo->x_focus_frame = frame;
4740
4741 if (old_focus && old_focus->auto_lower)
4742 if (FRAME_GTK_OUTER_WIDGET (old_focus))
4743 gdk_window_lower (gtk_widget_get_window
4744 (FRAME_GTK_OUTER_WIDGET (old_focus)));
4745
4746 if (dpyinfo->x_focus_frame && dpyinfo->x_focus_frame->auto_raise)
4747 if (FRAME_GTK_OUTER_WIDGET (dpyinfo->x_focus_frame))
4748 gdk_window_raise (gtk_widget_get_window
4749 (FRAME_GTK_OUTER_WIDGET (dpyinfo->x_focus_frame)));
4750 }
4751
4752 pgtk_frame_rehighlight (dpyinfo);
4753 }
4754
4755 static void
4756 pgtk_buffer_flipping_unblocked_hook (struct frame *f)
4757 {
4758 block_input ();
4759 flip_cr_context (f);
4760 gtk_widget_queue_draw (FRAME_GTK_WIDGET (f));
4761 unblock_input ();
4762 }
4763
4764 static struct terminal *
4765 pgtk_create_terminal (struct pgtk_display_info *dpyinfo)
4766 {
4767 struct terminal *terminal;
4768
4769 terminal = create_terminal (output_pgtk, &pgtk_redisplay_interface);
4770
4771 terminal->display_info.pgtk = dpyinfo;
4772 dpyinfo->terminal = terminal;
4773
4774 terminal->clear_frame_hook = pgtk_clear_frame;
4775 terminal->ring_bell_hook = pgtk_ring_bell;
4776 terminal->toggle_invisible_pointer_hook = pgtk_toggle_invisible_pointer;
4777 terminal->update_begin_hook = pgtk_update_begin;
4778 terminal->update_end_hook = pgtk_update_end;
4779 terminal->read_socket_hook = pgtk_read_socket;
4780 terminal->frame_up_to_date_hook = pgtk_frame_up_to_date;
4781 terminal->mouse_position_hook = pgtk_mouse_position;
4782 terminal->frame_rehighlight_hook = pgtk_frame_rehighlight_hook;
4783 terminal->buffer_flipping_unblocked_hook = pgtk_buffer_flipping_unblocked_hook;
4784 terminal->frame_raise_lower_hook = pgtk_frame_raise_lower;
4785 terminal->frame_visible_invisible_hook = pgtk_make_frame_visible_invisible;
4786 terminal->fullscreen_hook = pgtk_fullscreen_hook;
4787 terminal->menu_show_hook = pgtk_menu_show;
4788 terminal->activate_menubar_hook = pgtk_activate_menubar;
4789 terminal->popup_dialog_hook = pgtk_popup_dialog;
4790 terminal->change_tab_bar_height_hook = pgtk_change_tab_bar_height;
4791 terminal->set_vertical_scroll_bar_hook = pgtk_set_vertical_scroll_bar;
4792 terminal->set_horizontal_scroll_bar_hook = pgtk_set_horizontal_scroll_bar;
4793 terminal->condemn_scroll_bars_hook = pgtk_condemn_scroll_bars;
4794 terminal->redeem_scroll_bar_hook = pgtk_redeem_scroll_bar;
4795 terminal->judge_scroll_bars_hook = pgtk_judge_scroll_bars;
4796 terminal->get_string_resource_hook = pgtk_get_string_resource;
4797 terminal->delete_frame_hook = pgtk_destroy_window;
4798 terminal->delete_terminal_hook = pgtk_delete_terminal;
4799 terminal->query_frame_background_color = pgtk_query_frame_background_color;
4800 terminal->defined_color_hook = pgtk_defined_color;
4801 terminal->set_new_font_hook = pgtk_new_font;
4802 terminal->set_bitmap_icon_hook = pgtk_bitmap_icon;
4803 terminal->implicit_set_name_hook = pgtk_implicitly_set_name;
4804 terminal->iconify_frame_hook = pgtk_iconify_frame;
4805 terminal->set_scroll_bar_default_width_hook
4806 = pgtk_set_scroll_bar_default_width;
4807 terminal->set_scroll_bar_default_height_hook
4808 = pgtk_set_scroll_bar_default_height;
4809 terminal->set_window_size_hook = pgtk_set_window_size;
4810 terminal->query_colors = pgtk_query_colors;
4811 terminal->get_focus_frame = pgtk_get_focus_frame;
4812 terminal->focus_frame_hook = pgtk_focus_frame;
4813 terminal->set_frame_offset_hook = pgtk_set_offset;
4814 terminal->free_pixmap = pgtk_free_pixmap;
4815 terminal->toolkit_position_hook = pgtk_toolkit_position;
4816
4817
4818
4819 return terminal;
4820 }
4821
4822 struct pgtk_window_is_of_frame_recursive_t
4823 {
4824 GdkWindow *window;
4825 bool result;
4826 GtkWidget *emacs_gtk_fixed;
4827 };
4828
4829 static void
4830 pgtk_window_is_of_frame_recursive (GtkWidget *widget, gpointer data)
4831 {
4832 struct pgtk_window_is_of_frame_recursive_t *datap = data;
4833
4834 if (datap->result)
4835 return;
4836
4837 if (EMACS_IS_FIXED (widget) && widget != datap->emacs_gtk_fixed)
4838 return;
4839
4840 if (gtk_widget_get_window (widget) == datap->window)
4841 {
4842 datap->result = true;
4843 return;
4844 }
4845
4846 if (GTK_IS_CONTAINER (widget))
4847 gtk_container_foreach (GTK_CONTAINER (widget),
4848 pgtk_window_is_of_frame_recursive, datap);
4849 }
4850
4851 static bool
4852 pgtk_window_is_of_frame (struct frame *f, GdkWindow *window)
4853 {
4854 struct pgtk_window_is_of_frame_recursive_t data;
4855 data.window = window;
4856 data.result = false;
4857 data.emacs_gtk_fixed = FRAME_GTK_WIDGET (f);
4858 pgtk_window_is_of_frame_recursive (FRAME_WIDGET (f), &data);
4859 return data.result;
4860 }
4861
4862
4863
4864 static struct frame *
4865 pgtk_any_window_to_frame (GdkWindow *window)
4866 {
4867 Lisp_Object tail, frame;
4868 struct frame *f, *found = NULL;
4869
4870 if (window == NULL)
4871 return NULL;
4872
4873 FOR_EACH_FRAME (tail, frame)
4874 {
4875 if (found)
4876 break;
4877 f = XFRAME (frame);
4878 if (FRAME_PGTK_P (f))
4879 {
4880 if (pgtk_window_is_of_frame (f, window))
4881 found = f;
4882 }
4883 }
4884
4885 return found;
4886 }
4887
4888 static gboolean
4889 pgtk_handle_event (GtkWidget *widget, GdkEvent *event, gpointer *data)
4890 {
4891 struct frame *f;
4892 union buffered_input_event inev;
4893 GtkWidget *frame_widget;
4894 gint x, y;
4895
4896 if (event->type == GDK_TOUCHPAD_PINCH
4897 && (event->touchpad_pinch.phase
4898 != GDK_TOUCHPAD_GESTURE_PHASE_END))
4899 {
4900 f = pgtk_any_window_to_frame (gtk_widget_get_window (widget));
4901 frame_widget = FRAME_GTK_WIDGET (f);
4902
4903 gtk_widget_translate_coordinates (widget, frame_widget,
4904 lrint (event->touchpad_pinch.x),
4905 lrint (event->touchpad_pinch.y),
4906 &x, &y);
4907 if (f)
4908 {
4909
4910 inev.ie.kind = PINCH_EVENT;
4911 XSETFRAME (inev.ie.frame_or_window, f);
4912 XSETINT (inev.ie.x, x);
4913 XSETINT (inev.ie.y, y);
4914 inev.ie.arg = list4 (make_float (event->touchpad_pinch.dx),
4915 make_float (event->touchpad_pinch.dy),
4916 make_float (event->touchpad_pinch.scale),
4917 make_float (event->touchpad_pinch.angle_delta));
4918 inev.ie.modifiers = pgtk_gtk_to_emacs_modifiers (FRAME_DISPLAY_INFO (f),
4919 event->touchpad_pinch.state);
4920 inev.ie.device
4921 = pgtk_get_device_for_event (FRAME_DISPLAY_INFO (f), event);
4922 evq_enqueue (&inev);
4923 }
4924
4925 return TRUE;
4926 }
4927 return FALSE;
4928 }
4929
4930 static void
4931 pgtk_fill_rectangle (struct frame *f, unsigned long color, int x, int y,
4932 int width, int height, bool respect_alpha_background)
4933 {
4934 cairo_t *cr;
4935 cr = pgtk_begin_cr_clip (f);
4936 pgtk_set_cr_source_with_color (f, color, respect_alpha_background);
4937 cairo_rectangle (cr, x, y, width, height);
4938 cairo_fill (cr);
4939 pgtk_end_cr_clip (f);
4940 }
4941
4942 void
4943 pgtk_clear_under_internal_border (struct frame *f)
4944 {
4945 if (FRAME_INTERNAL_BORDER_WIDTH (f) > 0
4946 && (!FRAME_GTK_OUTER_WIDGET (f)
4947 || gtk_widget_get_realized (FRAME_GTK_OUTER_WIDGET (f))))
4948 {
4949 int border = FRAME_INTERNAL_BORDER_WIDTH (f);
4950 int width = FRAME_PIXEL_WIDTH (f);
4951 int height = FRAME_PIXEL_HEIGHT (f);
4952 int margin = FRAME_TOP_MARGIN_HEIGHT (f);
4953 int face_id =
4954 (FRAME_PARENT_FRAME (f)
4955 ? (!NILP (Vface_remapping_alist)
4956 ? lookup_basic_face (NULL, f, CHILD_FRAME_BORDER_FACE_ID)
4957 : CHILD_FRAME_BORDER_FACE_ID)
4958 : (!NILP (Vface_remapping_alist)
4959 ? lookup_basic_face (NULL, f, INTERNAL_BORDER_FACE_ID)
4960 : INTERNAL_BORDER_FACE_ID));
4961 struct face *face = FACE_FROM_ID_OR_NULL (f, face_id);
4962
4963 block_input ();
4964
4965 if (face)
4966 {
4967 #define x_fill_rectangle(f, gc, x, y, w, h) \
4968 fill_background_by_face (f, face, x, y, w, h)
4969 x_fill_rectangle (f, gc, 0, margin, width, border);
4970 x_fill_rectangle (f, gc, 0, 0, border, height);
4971 x_fill_rectangle (f, gc, width - border, 0, border, height);
4972 x_fill_rectangle (f, gc, 0, height - border, width, border);
4973 #undef x_fill_rectangle
4974 }
4975 else
4976 {
4977 #define x_clear_area(f, x, y, w, h) pgtk_clear_area (f, x, y, w, h)
4978 x_clear_area (f, 0, 0, border, height);
4979 x_clear_area (f, 0, margin, width, border);
4980 x_clear_area (f, width - border, 0, border, height);
4981 x_clear_area (f, 0, height - border, width, border);
4982 #undef x_clear_area
4983 }
4984
4985 unblock_input ();
4986 }
4987 }
4988
4989 static gboolean
4990 pgtk_handle_draw (GtkWidget *widget, cairo_t *cr, gpointer *data)
4991 {
4992 struct frame *f;
4993
4994 GdkWindow *win = gtk_widget_get_window (widget);
4995
4996 if (win != NULL)
4997 {
4998 cairo_surface_t *src = NULL;
4999 f = pgtk_any_window_to_frame (win);
5000 if (f != NULL)
5001 {
5002 src = FRAME_X_OUTPUT (f)->cr_surface_visible_bell;
5003 if (src == NULL && FRAME_CR_ACTIVE_CONTEXT (f) != NULL)
5004 src = cairo_get_target (FRAME_CR_ACTIVE_CONTEXT (f));
5005 }
5006 if (src != NULL)
5007 {
5008 cairo_set_source_surface (cr, src, 0, 0);
5009 cairo_paint (cr);
5010 }
5011 }
5012 return FALSE;
5013 }
5014
5015 static void
5016 size_allocate (GtkWidget *widget, GtkAllocation *alloc,
5017 gpointer user_data)
5018 {
5019 struct frame *f = pgtk_any_window_to_frame (gtk_widget_get_window (widget));
5020
5021 if (!f)
5022 f = user_data;
5023
5024 if (f)
5025 {
5026 xg_frame_resized (f, alloc->width, alloc->height);
5027 pgtk_cr_update_surface_desired_size (f, alloc->width, alloc->height, false);
5028 }
5029 }
5030
5031 static void
5032 get_modifier_values (int *mod_ctrl, int *mod_meta, int *mod_alt,
5033 int *mod_hyper, int *mod_super)
5034 {
5035 Lisp_Object tem;
5036
5037 *mod_ctrl = ctrl_modifier;
5038 *mod_meta = meta_modifier;
5039 *mod_alt = alt_modifier;
5040 *mod_hyper = hyper_modifier;
5041 *mod_super = super_modifier;
5042
5043 tem = Fget (Vx_ctrl_keysym, Qmodifier_value);
5044 if (INTEGERP (tem))
5045 *mod_ctrl = XFIXNUM (tem) & INT_MAX;
5046 tem = Fget (Vx_alt_keysym, Qmodifier_value);
5047 if (INTEGERP (tem))
5048 *mod_alt = XFIXNUM (tem) & INT_MAX;
5049 tem = Fget (Vx_meta_keysym, Qmodifier_value);
5050 if (INTEGERP (tem))
5051 *mod_meta = XFIXNUM (tem) & INT_MAX;
5052 tem = Fget (Vx_hyper_keysym, Qmodifier_value);
5053 if (INTEGERP (tem))
5054 *mod_hyper = XFIXNUM (tem) & INT_MAX;
5055 tem = Fget (Vx_super_keysym, Qmodifier_value);
5056 if (INTEGERP (tem))
5057 *mod_super = XFIXNUM (tem) & INT_MAX;
5058 }
5059
5060 int
5061 pgtk_gtk_to_emacs_modifiers (struct pgtk_display_info *dpyinfo, int state)
5062 {
5063 int mod_ctrl;
5064 int mod_meta;
5065 int mod_alt;
5066 int mod_hyper;
5067 int mod_super;
5068 int mod;
5069
5070 get_modifier_values (&mod_ctrl, &mod_meta, &mod_alt, &mod_hyper,
5071 &mod_super);
5072
5073 mod = 0;
5074 if (state & GDK_SHIFT_MASK)
5075 mod |= shift_modifier;
5076 if (state & GDK_CONTROL_MASK)
5077 mod |= mod_ctrl;
5078 if (state & GDK_META_MASK || state & GDK_MOD1_MASK)
5079 mod |= mod_meta;
5080 if (state & GDK_SUPER_MASK)
5081 mod |= mod_super;
5082 if (state & GDK_HYPER_MASK)
5083 mod |= mod_hyper;
5084
5085 return mod;
5086 }
5087
5088 int
5089 pgtk_emacs_to_gtk_modifiers (struct pgtk_display_info *dpyinfo, int state)
5090 {
5091 int mod_ctrl;
5092 int mod_meta;
5093 int mod_alt;
5094 int mod_hyper;
5095 int mod_super;
5096 int mask;
5097
5098 get_modifier_values (&mod_ctrl, &mod_meta, &mod_alt, &mod_hyper,
5099 &mod_super);
5100
5101 mask = 0;
5102 if (state & mod_super)
5103 mask |= GDK_SUPER_MASK;
5104 if (state & mod_hyper)
5105 mask |= GDK_HYPER_MASK;
5106 if (state & shift_modifier)
5107 mask |= GDK_SHIFT_MASK;
5108 if (state & mod_ctrl)
5109 mask |= GDK_CONTROL_MASK;
5110 if (state & mod_meta)
5111 mask |= GDK_MOD1_MASK;
5112 return mask;
5113 }
5114
5115 #define IsCursorKey(keysym) (0xff50 <= (keysym) && (keysym) < 0xff60)
5116 #define IsMiscFunctionKey(keysym) (0xff60 <= (keysym) && (keysym) < 0xff6c)
5117 #define IsKeypadKey(keysym) (0xff80 <= (keysym) && (keysym) < 0xffbe)
5118 #define IsFunctionKey(keysym) (0xffbe <= (keysym) && (keysym) < 0xffe1)
5119 #define IsModifierKey(keysym) \
5120 ((((keysym) >= GDK_KEY_Shift_L) && ((keysym) <= GDK_KEY_Hyper_R)) \
5121 || (((keysym) >= GDK_KEY_ISO_Lock) && ((keysym) <= GDK_KEY_ISO_Level5_Lock)) \
5122 || ((keysym) == GDK_KEY_Mode_switch) \
5123 || ((keysym) == GDK_KEY_Num_Lock))
5124
5125
5126 void
5127 pgtk_enqueue_string (struct frame *f, gchar *str)
5128 {
5129 gunichar *ustr, *uptr;
5130
5131 uptr = ustr = g_utf8_to_ucs4 (str, -1, NULL, NULL, NULL);
5132 if (ustr == NULL)
5133 return;
5134 for (; *ustr != 0; ustr++)
5135 {
5136 union buffered_input_event inev;
5137 Lisp_Object c = make_fixnum (*ustr);
5138 EVENT_INIT (inev.ie);
5139 inev.ie.kind = (SINGLE_BYTE_CHAR_P (XFIXNAT (c))
5140 ? ASCII_KEYSTROKE_EVENT
5141 : MULTIBYTE_CHAR_KEYSTROKE_EVENT);
5142 inev.ie.arg = Qnil;
5143 inev.ie.code = XFIXNAT (c);
5144 XSETFRAME (inev.ie.frame_or_window, f);
5145 inev.ie.modifiers = 0;
5146 inev.ie.timestamp = 0;
5147 evq_enqueue (&inev);
5148 }
5149
5150 g_free (uptr);
5151 }
5152
5153 void
5154 pgtk_enqueue_preedit (struct frame *f, Lisp_Object preedit)
5155 {
5156 union buffered_input_event inev;
5157 EVENT_INIT (inev.ie);
5158 inev.ie.kind = PREEDIT_TEXT_EVENT;
5159 inev.ie.arg = preedit;
5160 inev.ie.code = 0;
5161 XSETFRAME (inev.ie.frame_or_window, f);
5162 inev.ie.modifiers = 0;
5163 inev.ie.timestamp = 0;
5164 evq_enqueue (&inev);
5165 }
5166
5167 static gboolean
5168 key_press_event (GtkWidget *widget, GdkEvent *event, gpointer *user_data)
5169 {
5170 union buffered_input_event inev;
5171 ptrdiff_t nbytes;
5172 Mouse_HLInfo *hlinfo;
5173 struct frame *f;
5174 struct pgtk_display_info *dpyinfo;
5175
5176 f = pgtk_any_window_to_frame (gtk_widget_get_window (widget));
5177 EVENT_INIT (inev.ie);
5178 hlinfo = MOUSE_HL_INFO (f);
5179 nbytes = 0;
5180
5181
5182
5183 if (!hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
5184 {
5185 clear_mouse_face (hlinfo);
5186 hlinfo->mouse_face_hidden = true;
5187 }
5188
5189 if (f != 0)
5190 {
5191 guint keysym, orig_keysym;
5192
5193
5194
5195
5196
5197
5198
5199
5200
5201
5202
5203 unsigned char copy_buffer[513];
5204 unsigned char *copy_bufptr = copy_buffer;
5205 int copy_bufsiz = sizeof (copy_buffer);
5206 int modifiers;
5207 Lisp_Object c;
5208 guint state;
5209
5210 dpyinfo = FRAME_DISPLAY_INFO (f);
5211
5212
5213
5214 dpyinfo->last_user_time = event->key.time;
5215
5216 state = event->key.state;
5217
5218
5219
5220
5221 if (!(event->key.state & (GDK_SUPER_MASK | GDK_HYPER_MASK)))
5222 {
5223 if (pgtk_im_filter_keypress (f, &event->key))
5224 return TRUE;
5225 }
5226
5227 state |= pgtk_emacs_to_gtk_modifiers (FRAME_DISPLAY_INFO (f),
5228 extra_keyboard_modifiers);
5229 modifiers = state;
5230
5231
5232
5233
5234
5235 state &= ~GDK_CONTROL_MASK;
5236 state &= ~(GDK_META_MASK
5237 | GDK_SUPER_MASK | GDK_HYPER_MASK | GDK_MOD1_MASK);
5238
5239 nbytes = event->key.length;
5240 if (nbytes > copy_bufsiz)
5241 nbytes = copy_bufsiz;
5242 memcpy (copy_bufptr, event->key.string, nbytes);
5243
5244 keysym = event->key.keyval;
5245 orig_keysym = keysym;
5246
5247
5248 XSETFRAME (inev.ie.frame_or_window, f);
5249 inev.ie.modifiers
5250 = pgtk_gtk_to_emacs_modifiers (FRAME_DISPLAY_INFO (f), modifiers);
5251 inev.ie.timestamp = event->key.time;
5252
5253
5254
5255 if (keysym >= 32 && keysym < 128)
5256
5257 {
5258 inev.ie.kind = ASCII_KEYSTROKE_EVENT;
5259 inev.ie.code = keysym;
5260
5261 inev.ie.device
5262 = pgtk_get_device_for_event (FRAME_DISPLAY_INFO (f), event);
5263 goto done;
5264 }
5265
5266
5267 if (keysym >= 0x01000000 && keysym <= 0x0110FFFF)
5268 {
5269 if (keysym < 0x01000080)
5270 inev.ie.kind = ASCII_KEYSTROKE_EVENT;
5271 else
5272 inev.ie.kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT;
5273 inev.ie.code = keysym & 0xFFFFFF;
5274
5275 inev.ie.device
5276 = pgtk_get_device_for_event (FRAME_DISPLAY_INFO (f), event);
5277 goto done;
5278 }
5279
5280
5281 if (HASH_TABLE_P (Vpgtk_keysym_table)
5282 && (c = Fgethash (make_fixnum (keysym),
5283 Vpgtk_keysym_table, Qnil), FIXNATP (c)))
5284 {
5285 inev.ie.kind = (SINGLE_BYTE_CHAR_P (XFIXNAT (c))
5286 ? ASCII_KEYSTROKE_EVENT
5287 : MULTIBYTE_CHAR_KEYSTROKE_EVENT);
5288 inev.ie.code = XFIXNAT (c);
5289
5290 inev.ie.device
5291 = pgtk_get_device_for_event (FRAME_DISPLAY_INFO (f), event);
5292 goto done;
5293 }
5294
5295
5296 if (((keysym >= GDK_KEY_BackSpace && keysym <= GDK_KEY_Escape)
5297 || keysym == GDK_KEY_Delete
5298 #ifdef GDK_KEY_ISO_Left_Tab
5299 || (keysym >= GDK_KEY_ISO_Left_Tab && keysym <= GDK_KEY_ISO_Enter)
5300 #endif
5301 || IsCursorKey (keysym)
5302 || IsMiscFunctionKey (keysym)
5303 #ifdef HPUX
5304
5305
5306
5307
5308 || (GDK_KEY_Select <= keysym && keysym < GDK_KEY_KP_Space)
5309 #endif
5310 #ifdef GDK_KEY_dead_circumflex
5311 || orig_keysym == GDK_KEY_dead_circumflex
5312 #endif
5313 #ifdef GDK_KEY_dead_grave
5314 || orig_keysym == GDK_KEY_dead_grave
5315 #endif
5316 #ifdef GDK_KEY_dead_tilde
5317 || orig_keysym == GDK_KEY_dead_tilde
5318 #endif
5319 #ifdef GDK_KEY_dead_diaeresis
5320 || orig_keysym == GDK_KEY_dead_diaeresis
5321 #endif
5322 #ifdef GDK_KEY_dead_macron
5323 || orig_keysym == GDK_KEY_dead_macron
5324 #endif
5325 #ifdef GDK_KEY_dead_degree
5326 || orig_keysym == GDK_KEY_dead_degree
5327 #endif
5328 #ifdef GDK_KEY_dead_acute
5329 || orig_keysym == GDK_KEY_dead_acute
5330 #endif
5331 #ifdef GDK_KEY_dead_cedilla
5332 || orig_keysym == GDK_KEY_dead_cedilla
5333 #endif
5334 #ifdef GDK_KEY_dead_breve
5335 || orig_keysym == GDK_KEY_dead_breve
5336 #endif
5337 #ifdef GDK_KEY_dead_ogonek
5338 || orig_keysym == GDK_KEY_dead_ogonek
5339 #endif
5340 #ifdef GDK_KEY_dead_caron
5341 || orig_keysym == GDK_KEY_dead_caron
5342 #endif
5343 #ifdef GDK_KEY_dead_doubleacute
5344 || orig_keysym == GDK_KEY_dead_doubleacute
5345 #endif
5346 #ifdef GDK_KEY_dead_abovedot
5347 || orig_keysym == GDK_KEY_dead_abovedot
5348 #endif
5349 || IsKeypadKey (keysym)
5350 || IsFunctionKey (keysym)
5351
5352 || (orig_keysym & (1 << 28))
5353 || (keysym != GDK_KEY_VoidSymbol && nbytes == 0))
5354 && !(event->key.is_modifier
5355 || IsModifierKey (orig_keysym)
5356
5357
5358
5359
5360
5361 #if defined GDK_KEY_ISO_Lock && defined GDK_KEY_ISO_Last_Group_Lock
5362 || (GDK_KEY_ISO_Lock <= orig_keysym
5363 && orig_keysym <= GDK_KEY_ISO_Last_Group_Lock)
5364 #endif
5365 ))
5366 {
5367
5368
5369 inev.ie.kind = NON_ASCII_KEYSTROKE_EVENT;
5370 inev.ie.code = keysym;
5371
5372 inev.ie.device
5373 = pgtk_get_device_for_event (FRAME_DISPLAY_INFO (f), event);
5374 goto done;
5375 }
5376
5377 {
5378 inev.ie.kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT;
5379 inev.ie.arg = make_unibyte_string ((char *) copy_bufptr, nbytes);
5380 inev.ie.device
5381 = pgtk_get_device_for_event (FRAME_DISPLAY_INFO (f), event);
5382
5383 if (keysym == GDK_KEY_VoidSymbol)
5384 goto done;
5385 }
5386 }
5387
5388 done:
5389 if (inev.ie.kind != NO_EVENT)
5390 {
5391 XSETFRAME (inev.ie.frame_or_window, f);
5392 evq_enqueue (&inev);
5393 }
5394
5395 return TRUE;
5396 }
5397
5398 static struct pgtk_display_info *
5399 pgtk_display_info_for_display (GdkDisplay *dpy)
5400 {
5401 struct pgtk_display_info *dpyinfo;
5402
5403 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
5404 {
5405 if (dpyinfo->display == dpy)
5406 return dpyinfo;
5407 }
5408
5409 return NULL;
5410 }
5411
5412 static gboolean
5413 key_release_event (GtkWidget *widget,
5414 GdkEvent *event,
5415 gpointer *user_data)
5416 {
5417 GdkDisplay *display;
5418 struct pgtk_display_info *dpyinfo;
5419
5420 display = gtk_widget_get_display (widget);
5421 dpyinfo = pgtk_display_info_for_display (display);
5422
5423 if (dpyinfo)
5424
5425
5426
5427 dpyinfo->last_user_time = event->key.time;
5428
5429 return TRUE;
5430 }
5431
5432 static gboolean
5433 configure_event (GtkWidget *widget,
5434 GdkEvent *event,
5435 gpointer *user_data)
5436 {
5437 struct frame *f = pgtk_any_window_to_frame (event->configure.window);
5438
5439 if (f && widget == FRAME_GTK_OUTER_WIDGET (f))
5440 {
5441 if (any_help_event_p)
5442 {
5443 Lisp_Object frame;
5444 if (f)
5445 XSETFRAME (frame, f);
5446 else
5447 frame = Qnil;
5448 help_echo_string = Qnil;
5449 gen_help_event (Qnil, frame, Qnil, Qnil, 0);
5450 }
5451
5452 if (f->win_gravity == NorthWestGravity)
5453 gtk_window_get_position (GTK_WINDOW (widget),
5454 &f->left_pos, &f->top_pos);
5455 else
5456 {
5457 f->top_pos = event->configure.y;
5458 f->left_pos = event->configure.x;
5459 }
5460 }
5461 return FALSE;
5462 }
5463
5464 static gboolean
5465 map_event (GtkWidget *widget,
5466 GdkEvent *event,
5467 gpointer *user_data)
5468 {
5469 struct frame *f = pgtk_any_window_to_frame (event->any.window);
5470 union buffered_input_event inev;
5471
5472 EVENT_INIT (inev.ie);
5473 inev.ie.kind = NO_EVENT;
5474 inev.ie.arg = Qnil;
5475
5476 if (f)
5477 {
5478 bool iconified = FRAME_ICONIFIED_P (f);
5479
5480
5481
5482 if (!FRAME_X_OUTPUT (f)->has_been_visible)
5483 set_fullscreen_state (f);
5484
5485 if (!iconified)
5486 {
5487
5488
5489 if (FRAME_Z_GROUP (f) == z_group_above)
5490 pgtk_set_z_group (f, Qabove, Qnil);
5491 else if (FRAME_Z_GROUP (f) == z_group_below)
5492 pgtk_set_z_group (f, Qbelow, Qnil);
5493 }
5494
5495 SET_FRAME_VISIBLE (f, 1);
5496 SET_FRAME_ICONIFIED (f, false);
5497 FRAME_X_OUTPUT (f)->has_been_visible = true;
5498
5499 if (iconified)
5500 {
5501 inev.ie.kind = DEICONIFY_EVENT;
5502 XSETFRAME (inev.ie.frame_or_window, f);
5503 }
5504 }
5505
5506 if (inev.ie.kind != NO_EVENT)
5507 evq_enqueue (&inev);
5508 return FALSE;
5509 }
5510
5511 static gboolean
5512 window_state_event (GtkWidget *widget,
5513 GdkEvent *event,
5514 gpointer *user_data)
5515 {
5516 struct frame *f = pgtk_any_window_to_frame (event->window_state.window);
5517 GdkWindowState new_state;
5518 union buffered_input_event inev;
5519
5520 new_state = event->window_state.new_window_state;
5521
5522 EVENT_INIT (inev.ie);
5523 inev.ie.kind = NO_EVENT;
5524 inev.ie.arg = Qnil;
5525
5526 if (new_state & GDK_WINDOW_STATE_FULLSCREEN)
5527 store_frame_param (f, Qfullscreen, Qfullboth);
5528 else if (new_state & GDK_WINDOW_STATE_MAXIMIZED)
5529 store_frame_param (f, Qfullscreen, Qmaximized);
5530 else if ((new_state & GDK_WINDOW_STATE_TOP_TILED)
5531 && (new_state & GDK_WINDOW_STATE_BOTTOM_TILED)
5532 && !(new_state & GDK_WINDOW_STATE_TOP_RESIZABLE)
5533 && !(new_state & GDK_WINDOW_STATE_BOTTOM_RESIZABLE))
5534 store_frame_param (f, Qfullscreen, Qfullheight);
5535 else if ((new_state & GDK_WINDOW_STATE_LEFT_TILED)
5536 && (new_state & GDK_WINDOW_STATE_RIGHT_TILED)
5537 && !(new_state & GDK_WINDOW_STATE_LEFT_RESIZABLE)
5538 && !(new_state & GDK_WINDOW_STATE_RIGHT_RESIZABLE))
5539 store_frame_param (f, Qfullscreen, Qfullwidth);
5540 else
5541 store_frame_param (f, Qfullscreen, Qnil);
5542
5543
5544
5545
5546
5547
5548
5549
5550
5551
5552
5553
5554
5555
5556
5557
5558
5559
5560
5561
5562 if (new_state & GDK_WINDOW_STATE_ICONIFIED)
5563 {
5564 SET_FRAME_ICONIFIED (f, true);
5565 SET_FRAME_VISIBLE (f, false);
5566 }
5567 else
5568 {
5569 FRAME_X_OUTPUT (f)->has_been_visible = true;
5570 inev.ie.kind = DEICONIFY_EVENT;
5571 XSETFRAME (inev.ie.frame_or_window, f);
5572 SET_FRAME_ICONIFIED (f, false);
5573 SET_FRAME_VISIBLE (f, true);
5574 }
5575
5576 if (new_state & GDK_WINDOW_STATE_STICKY)
5577 store_frame_param (f, Qsticky, Qt);
5578 else
5579 store_frame_param (f, Qsticky, Qnil);
5580
5581 if (inev.ie.kind != NO_EVENT)
5582 evq_enqueue (&inev);
5583 return FALSE;
5584 }
5585
5586 static gboolean
5587 delete_event (GtkWidget *widget,
5588 GdkEvent *event, gpointer *user_data)
5589 {
5590 struct frame *f = pgtk_any_window_to_frame (event->any.window);
5591 union buffered_input_event inev;
5592
5593 EVENT_INIT (inev.ie);
5594 inev.ie.kind = NO_EVENT;
5595 inev.ie.arg = Qnil;
5596
5597 if (f)
5598 {
5599 inev.ie.kind = DELETE_WINDOW_EVENT;
5600 XSETFRAME (inev.ie.frame_or_window, f);
5601 }
5602
5603 if (inev.ie.kind != NO_EVENT)
5604 evq_enqueue (&inev);
5605 return TRUE;
5606 }
5607
5608
5609
5610
5611
5612
5613
5614
5615
5616
5617 static void
5618 pgtk_focus_changed (gboolean is_enter, int state,
5619 struct pgtk_display_info *dpyinfo, struct frame *frame,
5620 union buffered_input_event *bufp)
5621 {
5622 if (is_enter)
5623 {
5624 if (dpyinfo->x_focus_event_frame != frame)
5625 {
5626 pgtk_new_focus_frame (dpyinfo, frame);
5627 dpyinfo->x_focus_event_frame = frame;
5628
5629
5630
5631
5632 bufp->ie.arg = (((NILP (Vterminal_frame)
5633 || !FRAME_PGTK_P (XFRAME (Vterminal_frame))
5634 || EQ (Fdaemonp (), Qt))
5635 && CONSP (Vframe_list)
5636 && !NILP (XCDR (Vframe_list))) ? Qt : Qnil);
5637 bufp->ie.kind = FOCUS_IN_EVENT;
5638 XSETFRAME (bufp->ie.frame_or_window, frame);
5639 }
5640
5641 frame->output_data.pgtk->focus_state |= state;
5642
5643 }
5644 else
5645 {
5646 frame->output_data.pgtk->focus_state &= ~state;
5647
5648 if (dpyinfo->x_focus_event_frame == frame)
5649 {
5650 dpyinfo->x_focus_event_frame = 0;
5651 pgtk_new_focus_frame (dpyinfo, NULL);
5652
5653 bufp->ie.kind = FOCUS_OUT_EVENT;
5654 XSETFRAME (bufp->ie.frame_or_window, frame);
5655 }
5656
5657 if (frame->pointer_invisible)
5658 pgtk_toggle_invisible_pointer (frame, false);
5659 }
5660 }
5661
5662 static gboolean
5663 enter_notify_event (GtkWidget *widget, GdkEvent *event,
5664 gpointer *user_data)
5665 {
5666 union buffered_input_event inev;
5667 struct frame *frame
5668 = pgtk_any_window_to_frame (gtk_widget_get_window (widget));
5669
5670 if (frame == NULL)
5671 return FALSE;
5672
5673 struct pgtk_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
5674 struct frame *focus_frame = dpyinfo->x_focus_frame;
5675 int focus_state
5676 = focus_frame ? focus_frame->output_data.pgtk->focus_state : 0;
5677
5678 EVENT_INIT (inev.ie);
5679 inev.ie.kind = NO_EVENT;
5680 inev.ie.arg = Qnil;
5681
5682 if (event->crossing.detail != GDK_NOTIFY_INFERIOR
5683 && event->crossing.focus && !(focus_state & FOCUS_EXPLICIT))
5684 pgtk_focus_changed (TRUE, FOCUS_IMPLICIT, dpyinfo, frame, &inev);
5685 if (inev.ie.kind != NO_EVENT)
5686 evq_enqueue (&inev);
5687 return TRUE;
5688 }
5689
5690 static gboolean
5691 leave_notify_event (GtkWidget *widget, GdkEvent *event,
5692 gpointer *user_data)
5693 {
5694 union buffered_input_event inev;
5695 struct frame *frame
5696 = pgtk_any_window_to_frame (gtk_widget_get_window (widget));
5697
5698 if (frame == NULL)
5699 return FALSE;
5700
5701 struct pgtk_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
5702 struct frame *focus_frame = dpyinfo->x_focus_frame;
5703 int focus_state
5704 = focus_frame ? focus_frame->output_data.pgtk->focus_state : 0;
5705 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (frame);
5706
5707 if (frame == hlinfo->mouse_face_mouse_frame)
5708 {
5709
5710
5711 clear_mouse_face (hlinfo);
5712 hlinfo->mouse_face_mouse_frame = 0;
5713 }
5714
5715 EVENT_INIT (inev.ie);
5716 inev.ie.kind = NO_EVENT;
5717 inev.ie.arg = Qnil;
5718
5719 if (event->crossing.detail != GDK_NOTIFY_INFERIOR
5720 && event->crossing.focus && !(focus_state & FOCUS_EXPLICIT))
5721 pgtk_focus_changed (FALSE, FOCUS_IMPLICIT, dpyinfo, frame, &inev);
5722
5723 if (frame)
5724 {
5725 if (any_help_event_p)
5726 {
5727 Lisp_Object frame_obj;
5728 XSETFRAME (frame_obj, frame);
5729 help_echo_string = Qnil;
5730 gen_help_event (Qnil, frame_obj, Qnil, Qnil, 0);
5731 }
5732 }
5733
5734 if (inev.ie.kind != NO_EVENT)
5735 evq_enqueue (&inev);
5736 return TRUE;
5737 }
5738
5739 static gboolean
5740 focus_in_event (GtkWidget *widget, GdkEvent *event, gpointer *user_data)
5741 {
5742 union buffered_input_event inev;
5743 struct frame *frame
5744 = pgtk_any_window_to_frame (gtk_widget_get_window (widget));
5745
5746 if (frame == NULL)
5747 return TRUE;
5748
5749 EVENT_INIT (inev.ie);
5750 inev.ie.kind = NO_EVENT;
5751 inev.ie.arg = Qnil;
5752
5753 pgtk_focus_changed (TRUE, FOCUS_EXPLICIT,
5754 FRAME_DISPLAY_INFO (frame), frame, &inev);
5755 if (inev.ie.kind != NO_EVENT)
5756 evq_enqueue (&inev);
5757
5758 pgtk_im_focus_in (frame);
5759
5760 return TRUE;
5761 }
5762
5763 static gboolean
5764 focus_out_event (GtkWidget *widget, GdkEvent *event, gpointer *user_data)
5765 {
5766 union buffered_input_event inev;
5767 struct frame *frame
5768 = pgtk_any_window_to_frame (gtk_widget_get_window (widget));
5769
5770 if (frame == NULL)
5771 return TRUE;
5772
5773 EVENT_INIT (inev.ie);
5774 inev.ie.kind = NO_EVENT;
5775 inev.ie.arg = Qnil;
5776
5777 pgtk_focus_changed (FALSE, FOCUS_EXPLICIT,
5778 FRAME_DISPLAY_INFO (frame), frame, &inev);
5779 if (inev.ie.kind != NO_EVENT)
5780 evq_enqueue (&inev);
5781
5782 pgtk_im_focus_out (frame);
5783
5784 return TRUE;
5785 }
5786
5787
5788
5789
5790
5791
5792
5793
5794
5795 static bool
5796 note_mouse_movement (struct frame *frame,
5797 const GdkEventMotion *event)
5798 {
5799 XRectangle *r;
5800 struct pgtk_display_info *dpyinfo;
5801
5802 if (!FRAME_X_OUTPUT (frame))
5803 return false;
5804
5805 dpyinfo = FRAME_DISPLAY_INFO (frame);
5806 dpyinfo->last_mouse_movement_time = event->time;
5807 dpyinfo->last_mouse_motion_frame = frame;
5808 dpyinfo->last_mouse_motion_x = event->x;
5809 dpyinfo->last_mouse_motion_y = event->y;
5810
5811 if (event->window != gtk_widget_get_window (FRAME_GTK_WIDGET (frame)))
5812 {
5813 frame->mouse_moved = true;
5814 dpyinfo->last_mouse_scroll_bar = NULL;
5815 note_mouse_highlight (frame, -1, -1);
5816 dpyinfo->last_mouse_glyph_frame = NULL;
5817 frame->last_mouse_device
5818 = pgtk_get_device_for_event (FRAME_DISPLAY_INFO (frame),
5819 (GdkEvent *) event);
5820 return true;
5821 }
5822
5823
5824
5825 r = &dpyinfo->last_mouse_glyph;
5826 if (frame != dpyinfo->last_mouse_glyph_frame
5827 || event->x < r->x || event->x >= r->x + r->width
5828 || event->y < r->y || event->y >= r->y + r->height)
5829 {
5830 frame->mouse_moved = true;
5831 dpyinfo->last_mouse_scroll_bar = NULL;
5832 note_mouse_highlight (frame, event->x, event->y);
5833
5834 remember_mouse_glyph (frame, event->x, event->y, r);
5835 dpyinfo->last_mouse_glyph_frame = frame;
5836 frame->last_mouse_device
5837 = pgtk_get_device_for_event (FRAME_DISPLAY_INFO (frame),
5838 (GdkEvent *) event);
5839 return true;
5840 }
5841
5842 return false;
5843 }
5844
5845 static gboolean
5846 motion_notify_event (GtkWidget *widget, GdkEvent *event,
5847 gpointer *user_data)
5848 {
5849 union buffered_input_event inev;
5850 struct frame *f, *frame;
5851 struct pgtk_display_info *dpyinfo;
5852 Mouse_HLInfo *hlinfo;
5853
5854 EVENT_INIT (inev.ie);
5855 inev.ie.kind = NO_EVENT;
5856 inev.ie.arg = Qnil;
5857
5858 previous_help_echo_string = help_echo_string;
5859 help_echo_string = Qnil;
5860
5861 frame = pgtk_any_window_to_frame (gtk_widget_get_window (widget));
5862 dpyinfo = FRAME_DISPLAY_INFO (frame);
5863 f = (gui_mouse_grabbed (dpyinfo) ? dpyinfo->last_mouse_frame
5864 : pgtk_any_window_to_frame (gtk_widget_get_window (widget)));
5865 hlinfo = MOUSE_HL_INFO (f);
5866
5867 if (hlinfo->mouse_face_hidden)
5868 {
5869 hlinfo->mouse_face_hidden = false;
5870 clear_mouse_face (hlinfo);
5871 }
5872
5873 if (f && xg_event_is_for_scrollbar (f, event, false))
5874 f = 0;
5875
5876 if (f)
5877 {
5878
5879
5880
5881 if (!NILP (Vmouse_autoselect_window)
5882
5883
5884
5885
5886
5887 && !MINI_WINDOW_P (XWINDOW (selected_window))
5888
5889
5890 && (f == XFRAME (selected_frame) || !NILP (focus_follows_mouse)))
5891 {
5892 static Lisp_Object last_mouse_window;
5893 Lisp_Object window = window_from_coordinates
5894 (f, event->motion.x, event->motion.y, 0, false, false);
5895
5896
5897
5898
5899
5900
5901
5902
5903
5904 if (WINDOWP (window)
5905 && !EQ (window, last_mouse_window)
5906 && !EQ (window, selected_window))
5907 {
5908 inev.ie.kind = SELECT_WINDOW_EVENT;
5909 inev.ie.frame_or_window = window;
5910 }
5911
5912
5913 last_mouse_window = window;
5914 }
5915
5916 if (!note_mouse_movement (f, &event->motion))
5917 help_echo_string = previous_help_echo_string;
5918 }
5919 else
5920
5921
5922 clear_mouse_face (hlinfo);
5923
5924
5925
5926 int do_help = 0;
5927 if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
5928 do_help = 1;
5929
5930 if (inev.ie.kind != NO_EVENT)
5931 evq_enqueue (&inev);
5932
5933 if (do_help > 0)
5934 {
5935 Lisp_Object frame;
5936
5937 if (f)
5938 XSETFRAME (frame, f);
5939 else
5940 frame = Qnil;
5941
5942 any_help_event_p = true;
5943 gen_help_event (help_echo_string, frame, help_echo_window,
5944 help_echo_object, help_echo_pos);
5945 }
5946
5947 return TRUE;
5948 }
5949
5950
5951
5952
5953
5954
5955 static Lisp_Object
5956 construct_mouse_click (struct input_event *result,
5957 const GdkEventButton *event,
5958 struct frame *f)
5959 {
5960
5961
5962 result->kind = MOUSE_CLICK_EVENT;
5963 result->code = event->button - 1;
5964 result->timestamp = event->time;
5965 result->modifiers = (pgtk_gtk_to_emacs_modifiers (FRAME_DISPLAY_INFO (f),
5966 event->state)
5967 | (event->type == GDK_BUTTON_RELEASE
5968 ? up_modifier : down_modifier));
5969
5970 XSETINT (result->x, event->x);
5971 XSETINT (result->y, event->y);
5972 XSETFRAME (result->frame_or_window, f);
5973 result->arg = Qnil;
5974 result->device = pgtk_get_device_for_event (FRAME_DISPLAY_INFO (f),
5975 (GdkEvent *) event);
5976 return Qnil;
5977 }
5978
5979 static gboolean
5980 button_event (GtkWidget *widget, GdkEvent *event,
5981 gpointer *user_data)
5982 {
5983 union buffered_input_event inev;
5984 struct frame *f, *frame;
5985 struct pgtk_display_info *dpyinfo;
5986
5987
5988
5989 bool tab_bar_p = false;
5990 bool tool_bar_p = false;
5991 Lisp_Object tab_bar_arg = Qnil;
5992
5993 EVENT_INIT (inev.ie);
5994 inev.ie.kind = NO_EVENT;
5995 inev.ie.arg = Qnil;
5996
5997
5998 if (event->type != GDK_BUTTON_PRESS && event->type != GDK_BUTTON_RELEASE)
5999 return TRUE;
6000
6001 frame = pgtk_any_window_to_frame (gtk_widget_get_window (widget));
6002 dpyinfo = FRAME_DISPLAY_INFO (frame);
6003
6004 dpyinfo->last_mouse_glyph_frame = NULL;
6005
6006 if (gui_mouse_grabbed (dpyinfo))
6007 f = dpyinfo->last_mouse_frame;
6008 else
6009 {
6010 f = pgtk_any_window_to_frame (gtk_widget_get_window (widget));
6011
6012 if (f && event->button.type == GDK_BUTTON_PRESS
6013 && !FRAME_NO_ACCEPT_FOCUS (f))
6014 {
6015
6016
6017
6018
6019 struct frame *hf = dpyinfo->highlight_frame;
6020
6021 if (FRAME_PARENT_FRAME (f) || (hf && frame_ancestor_p (f, hf)))
6022 {
6023 block_input ();
6024 gtk_widget_grab_focus (FRAME_GTK_WIDGET (f));
6025
6026 if (FRAME_GTK_OUTER_WIDGET (f))
6027 gtk_window_present (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)));
6028 unblock_input ();
6029 }
6030 }
6031 }
6032
6033
6034
6035 dpyinfo->last_user_time = event->button.time;
6036
6037 if (f)
6038 {
6039
6040 if (WINDOWP (f->tab_bar_window)
6041 && WINDOW_TOTAL_LINES (XWINDOW (f->tab_bar_window)))
6042 {
6043 Lisp_Object window;
6044 int x = event->button.x;
6045 int y = event->button.y;
6046
6047 window = window_from_coordinates (f, x, y, 0, true, true);
6048 tab_bar_p = EQ (window, f->tab_bar_window);
6049
6050 if (tab_bar_p)
6051 tab_bar_arg = handle_tab_bar_click
6052 (f, x, y, event->type == GDK_BUTTON_PRESS,
6053 pgtk_gtk_to_emacs_modifiers (dpyinfo, event->button.state));
6054 }
6055
6056 if (!(tab_bar_p && NILP (tab_bar_arg)) && !tool_bar_p)
6057 {
6058 if (ignore_next_mouse_click_timeout)
6059 {
6060 if (event->type == GDK_BUTTON_PRESS
6061 && event->button.time > ignore_next_mouse_click_timeout)
6062 {
6063 ignore_next_mouse_click_timeout = 0;
6064 construct_mouse_click (&inev.ie, &event->button, f);
6065 }
6066 if (event->type == GDK_BUTTON_RELEASE)
6067 ignore_next_mouse_click_timeout = 0;
6068 }
6069 else
6070 construct_mouse_click (&inev.ie, &event->button, f);
6071
6072 if (!NILP (tab_bar_arg))
6073 inev.ie.arg = tab_bar_arg;
6074 }
6075 }
6076
6077 if (event->type == GDK_BUTTON_PRESS)
6078 {
6079 dpyinfo->grabbed |= (1 << event->button.button);
6080 dpyinfo->last_mouse_frame = f;
6081
6082 if (dpyinfo->last_click_event != NULL)
6083 gdk_event_free (dpyinfo->last_click_event);
6084 dpyinfo->last_click_event = gdk_event_copy (event);
6085 }
6086 else
6087 dpyinfo->grabbed &= ~(1 << event->button.button);
6088
6089
6090
6091
6092 if (f != 0)
6093 f->mouse_moved = false;
6094
6095 if (inev.ie.kind != NO_EVENT)
6096 evq_enqueue (&inev);
6097 return TRUE;
6098 }
6099
6100 static gboolean
6101 scroll_event (GtkWidget *widget, GdkEvent *event, gpointer *user_data)
6102 {
6103 union buffered_input_event inev;
6104 struct frame *f, *frame;
6105 struct pgtk_display_info *dpyinfo;
6106 GdkScrollDirection dir;
6107 double delta_x, delta_y;
6108
6109 EVENT_INIT (inev.ie);
6110 inev.ie.kind = NO_EVENT;
6111 inev.ie.arg = Qnil;
6112
6113 frame = pgtk_any_window_to_frame (gtk_widget_get_window (widget));
6114 dpyinfo = FRAME_DISPLAY_INFO (frame);
6115
6116 if (gui_mouse_grabbed (dpyinfo))
6117 f = dpyinfo->last_mouse_frame;
6118 else
6119 f = pgtk_any_window_to_frame (gtk_widget_get_window (widget));
6120
6121 inev.ie.kind = NO_EVENT;
6122 inev.ie.timestamp = event->scroll.time;
6123 inev.ie.modifiers
6124 = pgtk_gtk_to_emacs_modifiers (FRAME_DISPLAY_INFO (f), event->scroll.state);
6125 XSETINT (inev.ie.x, event->scroll.x);
6126 XSETINT (inev.ie.y, event->scroll.y);
6127 XSETFRAME (inev.ie.frame_or_window, f);
6128 inev.ie.arg = Qnil;
6129
6130 if (gdk_event_is_scroll_stop_event (event))
6131 {
6132 inev.ie.kind = TOUCH_END_EVENT;
6133 inev.ie.device
6134 = pgtk_get_device_for_event (FRAME_DISPLAY_INFO (f), event);
6135 evq_enqueue (&inev);
6136 return TRUE;
6137 }
6138
6139 if (gdk_event_get_scroll_direction (event, &dir))
6140 {
6141 switch (dir)
6142 {
6143 case GDK_SCROLL_UP:
6144 inev.ie.kind = WHEEL_EVENT;
6145 inev.ie.modifiers |= up_modifier;
6146 break;
6147 case GDK_SCROLL_DOWN:
6148 inev.ie.kind = WHEEL_EVENT;
6149 inev.ie.modifiers |= down_modifier;
6150 break;
6151 case GDK_SCROLL_LEFT:
6152 inev.ie.kind = HORIZ_WHEEL_EVENT;
6153 inev.ie.modifiers |= up_modifier;
6154 break;
6155 case GDK_SCROLL_RIGHT:
6156 inev.ie.kind = HORIZ_WHEEL_EVENT;
6157 inev.ie.modifiers |= down_modifier;
6158 break;
6159 case GDK_SCROLL_SMOOTH:
6160 break;
6161 }
6162 }
6163 else if (gdk_event_get_scroll_deltas (event, &delta_x, &delta_y))
6164 {
6165 if (!mwheel_coalesce_scroll_events)
6166 {
6167 inev.ie.kind = ((fabs (delta_x) > fabs (delta_y))
6168 ? HORIZ_WHEEL_EVENT
6169 : WHEEL_EVENT);
6170 inev.ie.modifiers |= (inev.ie.kind == HORIZ_WHEEL_EVENT
6171 ? (delta_x >= 0 ? up_modifier : down_modifier)
6172 : (delta_y >= 0 ? down_modifier : up_modifier));
6173 inev.ie.arg = list3 (Qnil, make_float (-delta_x * 100),
6174 make_float (-delta_y * 100));
6175 }
6176 else
6177 {
6178 dpyinfo->scroll.acc_x += delta_x;
6179 dpyinfo->scroll.acc_y += delta_y;
6180 if (dpyinfo->scroll.acc_y >= dpyinfo->scroll.y_per_line)
6181 {
6182 int nlines = dpyinfo->scroll.acc_y / dpyinfo->scroll.y_per_line;
6183 inev.ie.kind = WHEEL_EVENT;
6184 inev.ie.modifiers |= down_modifier;
6185 inev.ie.arg = list3 (make_fixnum (nlines),
6186 make_float (-dpyinfo->scroll.acc_x * 100),
6187 make_float (-dpyinfo->scroll.acc_y * 100));
6188 dpyinfo->scroll.acc_y -= dpyinfo->scroll.y_per_line * nlines;
6189 }
6190 else if (dpyinfo->scroll.acc_y <= -dpyinfo->scroll.y_per_line)
6191 {
6192 int nlines = -dpyinfo->scroll.acc_y / dpyinfo->scroll.y_per_line;
6193 inev.ie.kind = WHEEL_EVENT;
6194 inev.ie.modifiers |= up_modifier;
6195 inev.ie.arg = list3 (make_fixnum (nlines),
6196 make_float (-dpyinfo->scroll.acc_x * 100),
6197 make_float (-dpyinfo->scroll.acc_y * 100));
6198
6199 dpyinfo->scroll.acc_y -= -dpyinfo->scroll.y_per_line * nlines;
6200 }
6201 else if (dpyinfo->scroll.acc_x >= dpyinfo->scroll.x_per_char
6202 || !mwheel_coalesce_scroll_events)
6203 {
6204 int nchars = dpyinfo->scroll.acc_x / dpyinfo->scroll.x_per_char;
6205 inev.ie.kind = HORIZ_WHEEL_EVENT;
6206 inev.ie.modifiers |= up_modifier;
6207 inev.ie.arg = list3 (make_fixnum (nchars),
6208 make_float (-dpyinfo->scroll.acc_x * 100),
6209 make_float (-dpyinfo->scroll.acc_y * 100));
6210
6211 dpyinfo->scroll.acc_x -= dpyinfo->scroll.x_per_char * nchars;
6212 }
6213 else if (dpyinfo->scroll.acc_x <= -dpyinfo->scroll.x_per_char)
6214 {
6215 int nchars = -dpyinfo->scroll.acc_x / dpyinfo->scroll.x_per_char;
6216 inev.ie.kind = HORIZ_WHEEL_EVENT;
6217 inev.ie.modifiers |= down_modifier;
6218 inev.ie.arg = list3 (make_fixnum (nchars),
6219 make_float (-dpyinfo->scroll.acc_x * 100),
6220 make_float (-dpyinfo->scroll.acc_y * 100));
6221
6222 dpyinfo->scroll.acc_x -= -dpyinfo->scroll.x_per_char * nchars;
6223 }
6224 }
6225 }
6226
6227 if (inev.ie.kind != NO_EVENT)
6228 {
6229 inev.ie.device
6230 = pgtk_get_device_for_event (FRAME_DISPLAY_INFO (f), event);
6231 evq_enqueue (&inev);
6232 }
6233 return TRUE;
6234 }
6235
6236
6237
6238
6239
6240
6241 static GdkDragAction
6242 symbol_to_drag_action (Lisp_Object act)
6243 {
6244 if (EQ (act, Qcopy))
6245 return GDK_ACTION_COPY;
6246
6247 if (EQ (act, Qmove))
6248 return GDK_ACTION_MOVE;
6249
6250 if (EQ (act, Qlink))
6251 return GDK_ACTION_LINK;
6252
6253 if (EQ (act, Qprivate))
6254 return GDK_ACTION_PRIVATE;
6255
6256 if (NILP (act))
6257 return GDK_ACTION_DEFAULT;
6258
6259 signal_error ("Invalid drag acction", act);
6260 }
6261
6262 static Lisp_Object
6263 drag_action_to_symbol (GdkDragAction action)
6264 {
6265 switch (action)
6266 {
6267 case GDK_ACTION_COPY:
6268 return Qcopy;
6269
6270 case GDK_ACTION_MOVE:
6271 return Qmove;
6272
6273 case GDK_ACTION_LINK:
6274 return Qlink;
6275
6276 case GDK_ACTION_PRIVATE:
6277 return Qprivate;
6278
6279 case GDK_ACTION_DEFAULT:
6280 default:
6281 return Qnil;
6282 }
6283 }
6284
6285 void
6286 pgtk_update_drop_status (Lisp_Object action, Lisp_Object event_time)
6287 {
6288 guint32 time;
6289
6290 CONS_TO_INTEGER (event_time, guint32, time);
6291
6292 if (!current_drop_context || time < current_drop_time)
6293 return;
6294
6295 gdk_drag_status (current_drop_context,
6296 symbol_to_drag_action (action),
6297 time);
6298 }
6299
6300 void
6301 pgtk_finish_drop (Lisp_Object success, Lisp_Object event_time,
6302 Lisp_Object del)
6303 {
6304 guint32 time;
6305
6306 CONS_TO_INTEGER (event_time, guint32, time);
6307
6308 if (!current_drop_context || time < current_drop_time)
6309 return;
6310
6311 gtk_drag_finish (current_drop_context, !NILP (success),
6312 !NILP (del), time);
6313
6314 if (current_drop_context_drop)
6315 g_clear_pointer (¤t_drop_context,
6316 g_object_unref);
6317 }
6318
6319 static void
6320 drag_leave (GtkWidget *widget, GdkDragContext *context,
6321 guint time, gpointer user_data)
6322 {
6323 struct frame *f;
6324 union buffered_input_event inev;
6325
6326 f = pgtk_any_window_to_frame (gtk_widget_get_window (widget));
6327
6328 if (current_drop_context)
6329 {
6330 if (current_drop_context_drop)
6331 gtk_drag_finish (current_drop_context,
6332 FALSE, FALSE, current_drop_time);
6333
6334 g_clear_pointer (¤t_drop_context,
6335 g_object_unref);
6336 }
6337
6338 EVENT_INIT (inev.ie);
6339
6340 inev.ie.kind = DRAG_N_DROP_EVENT;
6341 inev.ie.modifiers = 0;
6342 inev.ie.arg = Qnil;
6343 inev.ie.timestamp = time;
6344
6345 XSETINT (inev.ie.x, 0);
6346 XSETINT (inev.ie.y, 0);
6347 XSETFRAME (inev.ie.frame_or_window, f);
6348
6349 evq_enqueue (&inev);
6350 }
6351
6352 static gboolean
6353 drag_motion (GtkWidget *widget, GdkDragContext *context,
6354 gint x, gint y, guint time)
6355
6356 {
6357 struct frame *f;
6358 union buffered_input_event inev;
6359 GdkAtom name;
6360 GdkDragAction suggestion;
6361
6362 f = pgtk_any_window_to_frame (gtk_widget_get_window (widget));
6363
6364 if (!f)
6365 return FALSE;
6366
6367 if (current_drop_context)
6368 {
6369 if (current_drop_context_drop)
6370 gtk_drag_finish (current_drop_context,
6371 FALSE, FALSE, current_drop_time);
6372
6373 g_clear_pointer (¤t_drop_context,
6374 g_object_unref);
6375 }
6376
6377 current_drop_context = g_object_ref (context);
6378 current_drop_time = time;
6379 current_drop_context_drop = false;
6380
6381 name = gdk_drag_get_selection (context);
6382 suggestion = gdk_drag_context_get_suggested_action (context);
6383
6384 EVENT_INIT (inev.ie);
6385
6386 inev.ie.kind = DRAG_N_DROP_EVENT;
6387 inev.ie.modifiers = 0;
6388 inev.ie.arg = list4 (Qlambda, intern (gdk_atom_name (name)),
6389 make_uint (time),
6390 drag_action_to_symbol (suggestion));
6391 inev.ie.timestamp = time;
6392
6393 XSETINT (inev.ie.x, x);
6394 XSETINT (inev.ie.y, y);
6395 XSETFRAME (inev.ie.frame_or_window, f);
6396
6397 evq_enqueue (&inev);
6398
6399 return TRUE;
6400 }
6401
6402 static gboolean
6403 drag_drop (GtkWidget *widget, GdkDragContext *context,
6404 int x, int y, guint time, gpointer user_data)
6405 {
6406 struct frame *f;
6407 union buffered_input_event inev;
6408 GdkAtom name;
6409 GdkDragAction selected_action;
6410
6411 f = pgtk_any_window_to_frame (gtk_widget_get_window (widget));
6412
6413 if (!f)
6414 return FALSE;
6415
6416 if (current_drop_context)
6417 {
6418 if (current_drop_context_drop)
6419 gtk_drag_finish (current_drop_context,
6420 FALSE, FALSE, current_drop_time);
6421
6422 g_clear_pointer (¤t_drop_context,
6423 g_object_unref);
6424 }
6425
6426 current_drop_context = g_object_ref (context);
6427 current_drop_time = time;
6428 current_drop_context_drop = true;
6429
6430 name = gdk_drag_get_selection (context);
6431 selected_action = gdk_drag_context_get_selected_action (context);
6432
6433 EVENT_INIT (inev.ie);
6434
6435 inev.ie.kind = DRAG_N_DROP_EVENT;
6436 inev.ie.modifiers = 0;
6437 inev.ie.arg = list4 (Qquote, intern (gdk_atom_name (name)),
6438 make_uint (time),
6439 drag_action_to_symbol (selected_action));
6440 inev.ie.timestamp = time;
6441
6442 XSETINT (inev.ie.x, x);
6443 XSETINT (inev.ie.y, y);
6444 XSETFRAME (inev.ie.frame_or_window, f);
6445
6446 evq_enqueue (&inev);
6447
6448 return TRUE;
6449 }
6450
6451 static void
6452 pgtk_monitors_changed_cb (GdkScreen *screen, gpointer user_data)
6453 {
6454 struct terminal *terminal;
6455 union buffered_input_event inev;
6456
6457 EVENT_INIT (inev.ie);
6458 terminal = user_data;
6459 inev.ie.kind = MONITORS_CHANGED_EVENT;
6460 XSETTERMINAL (inev.ie.arg, terminal);
6461
6462 evq_enqueue (&inev);
6463 }
6464
6465 static gboolean pgtk_selection_event (GtkWidget *, GdkEvent *, gpointer);
6466
6467 void
6468 pgtk_set_event_handler (struct frame *f)
6469 {
6470 if (f->tooltip)
6471 {
6472 g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "draw",
6473 G_CALLBACK (pgtk_handle_draw), NULL);
6474 return;
6475 }
6476
6477 gtk_drag_dest_set (FRAME_GTK_WIDGET (f), 0, NULL, 0,
6478 (GDK_ACTION_MOVE | GDK_ACTION_COPY
6479 | GDK_ACTION_LINK | GDK_ACTION_PRIVATE));
6480
6481 if (FRAME_GTK_OUTER_WIDGET (f))
6482 {
6483 g_signal_connect (G_OBJECT (FRAME_GTK_OUTER_WIDGET (f)),
6484 "window-state-event", G_CALLBACK (window_state_event),
6485 NULL);
6486 g_signal_connect (G_OBJECT (FRAME_GTK_OUTER_WIDGET (f)), "delete-event",
6487 G_CALLBACK (delete_event), NULL);
6488 g_signal_connect (G_OBJECT (FRAME_GTK_OUTER_WIDGET (f)), "event",
6489 G_CALLBACK (pgtk_handle_event), NULL);
6490 g_signal_connect (G_OBJECT (FRAME_GTK_OUTER_WIDGET (f)), "configure-event",
6491 G_CALLBACK (configure_event), NULL);
6492 }
6493
6494 g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "map-event",
6495 G_CALLBACK (map_event), NULL);
6496 g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "size-allocate",
6497 G_CALLBACK (size_allocate), f);
6498 g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "key-press-event",
6499 G_CALLBACK (key_press_event), NULL);
6500 g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "key-release-event",
6501 G_CALLBACK (key_release_event), NULL);
6502 g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "focus-in-event",
6503 G_CALLBACK (focus_in_event), NULL);
6504 g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "focus-out-event",
6505 G_CALLBACK (focus_out_event), NULL);
6506 g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "enter-notify-event",
6507 G_CALLBACK (enter_notify_event), NULL);
6508 g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "leave-notify-event",
6509 G_CALLBACK (leave_notify_event), NULL);
6510 g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "motion-notify-event",
6511 G_CALLBACK (motion_notify_event), NULL);
6512 g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "button-press-event",
6513 G_CALLBACK (button_event), NULL);
6514 g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "button-release-event",
6515 G_CALLBACK (button_event), NULL);
6516 g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "scroll-event",
6517 G_CALLBACK (scroll_event), NULL);
6518 g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "configure-event",
6519 G_CALLBACK (configure_event), NULL);
6520 g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "drag-leave",
6521 G_CALLBACK (drag_leave), NULL);
6522 g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "drag-motion",
6523 G_CALLBACK (drag_motion), NULL);
6524 g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "drag-drop",
6525 G_CALLBACK (drag_drop), NULL);
6526 g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "draw",
6527 G_CALLBACK (pgtk_handle_draw), NULL);
6528 g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "property-notify-event",
6529 G_CALLBACK (pgtk_selection_event), NULL);
6530 g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "selection-clear-event",
6531 G_CALLBACK (pgtk_selection_event), NULL);
6532 g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "selection-request-event",
6533 G_CALLBACK (pgtk_selection_event), NULL);
6534 g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "selection-notify-event",
6535 G_CALLBACK (pgtk_selection_event), NULL);
6536 g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "event",
6537 G_CALLBACK (pgtk_handle_event), NULL);
6538 }
6539
6540 static void
6541 my_log_handler (const gchar * log_domain, GLogLevelFlags log_level,
6542 const gchar * msg, gpointer user_data)
6543 {
6544 if (!strstr (msg, "g_set_prgname"))
6545 fprintf (stderr, "%s-WARNING **: %s", log_domain, msg);
6546 }
6547
6548
6549
6550 static bool
6551 same_x_server (const char *name1, const char *name2)
6552 {
6553 bool seen_colon = false;
6554 Lisp_Object sysname = Fsystem_name ();
6555 const char *system_name = SSDATA (sysname);
6556 ptrdiff_t system_name_length = SBYTES (sysname);
6557 ptrdiff_t length_until_period = 0;
6558
6559 while (system_name[length_until_period] != 0
6560 && system_name[length_until_period] != '.')
6561 length_until_period++;
6562
6563
6564 if (!strncmp (name1, "unix:", 5))
6565 name1 += 4;
6566 if (!strncmp (name2, "unix:", 5))
6567 name2 += 4;
6568
6569 if (!strncmp (name1, system_name, system_name_length)
6570 && name1[system_name_length] == ':')
6571 name1 += system_name_length;
6572 if (!strncmp (name2, system_name, system_name_length)
6573 && name2[system_name_length] == ':')
6574 name2 += system_name_length;
6575
6576 if (!strncmp (name1, system_name, length_until_period)
6577 && name1[length_until_period] == ':')
6578 name1 += length_until_period;
6579 if (!strncmp (name2, system_name, length_until_period)
6580 && name2[length_until_period] == ':')
6581 name2 += length_until_period;
6582
6583 for (; *name1 != '\0' && *name1 == *name2; name1++, name2++)
6584 {
6585 if (*name1 == ':')
6586 seen_colon = true;
6587 if (seen_colon && *name1 == '.')
6588 return true;
6589 }
6590 return (seen_colon
6591 && (*name1 == '.' || *name1 == '\0')
6592 && (*name2 == '.' || *name2 == '\0'));
6593 }
6594
6595 static struct frame *
6596 pgtk_find_selection_owner (GdkWindow *window)
6597 {
6598 Lisp_Object tail, tem;
6599 struct frame *f;
6600
6601 FOR_EACH_FRAME (tail, tem)
6602 {
6603 f = XFRAME (tem);
6604
6605 if (FRAME_PGTK_P (f)
6606 && (FRAME_GDK_WINDOW (f) == window))
6607 return f;
6608 }
6609
6610 return NULL;
6611 }
6612
6613 static gboolean
6614 pgtk_selection_event (GtkWidget *widget, GdkEvent *event,
6615 gpointer user_data)
6616 {
6617 struct frame *f;
6618 union buffered_input_event inev;
6619
6620 if (event->type == GDK_PROPERTY_NOTIFY)
6621 pgtk_handle_property_notify (&event->property);
6622 else if (event->type == GDK_SELECTION_CLEAR
6623 || event->type == GDK_SELECTION_REQUEST)
6624 {
6625 f = pgtk_find_selection_owner (event->selection.window);
6626
6627 if (f)
6628 {
6629 EVENT_INIT (inev.ie);
6630
6631 inev.sie.kind = (event->type == GDK_SELECTION_CLEAR
6632 ? SELECTION_CLEAR_EVENT
6633 : SELECTION_REQUEST_EVENT);
6634
6635 SELECTION_EVENT_DPYINFO (&inev.sie) = FRAME_DISPLAY_INFO (f);
6636 SELECTION_EVENT_SELECTION (&inev.sie) = event->selection.selection;
6637 SELECTION_EVENT_TIME (&inev.sie) = event->selection.time;
6638
6639 if (event->type == GDK_SELECTION_REQUEST)
6640 {
6641
6642
6643
6644
6645
6646
6647 SELECTION_EVENT_REQUESTOR (&inev.sie) = event->selection.requestor;
6648 SELECTION_EVENT_TARGET (&inev.sie) = event->selection.target;
6649 SELECTION_EVENT_PROPERTY (&inev.sie) = event->selection.property;
6650 }
6651
6652 evq_enqueue (&inev);
6653 return TRUE;
6654 }
6655 }
6656 else if (event->type == GDK_SELECTION_NOTIFY)
6657 pgtk_handle_selection_notify (&event->selection);
6658
6659 return FALSE;
6660 }
6661
6662
6663
6664
6665 static void
6666 pgtk_display_x_warning (GdkDisplay *display)
6667 {
6668 GtkWidget *dialog_widget, *label, *content_area;
6669 GtkDialog *dialog;
6670 GtkWindow *window;
6671 GdkScreen *screen;
6672
6673
6674
6675 if (strcmp (G_OBJECT_TYPE_NAME (display),
6676 "GdkX11Display"))
6677 return;
6678
6679 dialog_widget = gtk_dialog_new ();
6680 dialog = GTK_DIALOG (dialog_widget);
6681 window = GTK_WINDOW (dialog_widget);
6682 screen = gdk_display_get_default_screen (display);
6683 content_area = gtk_dialog_get_content_area (dialog);
6684
6685 gtk_window_set_title (window, "Warning");
6686 gtk_window_set_screen (window, screen);
6687
6688 label = gtk_label_new ("You are trying to run Emacs configured with"
6689 " the \"pure-GTK\" interface under the X Window"
6690 " System. That configuration is unsupported and"
6691 " will lead to sporadic crashes during transfer of"
6692 " large selection data. It will also lead to"
6693 " various problems with keyboard input.");
6694 gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
6695 gtk_container_add (GTK_CONTAINER (content_area), label);
6696 gtk_widget_show (label);
6697 gtk_widget_show (dialog_widget);
6698 }
6699
6700
6701
6702
6703
6704 struct pgtk_display_info *
6705 pgtk_term_init (Lisp_Object display_name, char *resource_name)
6706 {
6707 GdkDisplay *dpy;
6708 struct terminal *terminal;
6709 struct pgtk_display_info *dpyinfo;
6710 static int x_initialized = 0;
6711 static unsigned x_display_id = 0;
6712 static char *initial_display = NULL;
6713 char *dpy_name;
6714 static void *handle = NULL;
6715 Lisp_Object lisp_dpy_name = Qnil;
6716 GdkScreen *gscr;
6717 gdouble dpi;
6718
6719 block_input ();
6720
6721 if (!x_initialized)
6722 {
6723 any_help_event_p = false;
6724
6725 Fset_input_interrupt_mode (Qt);
6726 baud_rate = 19200;
6727
6728 #ifdef USE_CAIRO
6729 gui_init_fringe (&pgtk_redisplay_interface);
6730 #endif
6731
6732 ++x_initialized;
6733 }
6734
6735 dpy_name = SSDATA (display_name);
6736 if (strlen (dpy_name) == 0 && initial_display != NULL)
6737 dpy_name = initial_display;
6738 lisp_dpy_name = build_string (dpy_name);
6739
6740 {
6741 #define NUM_ARGV 10
6742 int argc;
6743 char *argv[NUM_ARGV];
6744 char **argv2 = argv;
6745 guint id;
6746
6747 if (x_initialized++ > 1)
6748 {
6749 xg_display_open (dpy_name, &dpy);
6750 }
6751 else
6752 {
6753 static char display_opt[] = "--display";
6754 static char name_opt[] = "--name";
6755
6756 for (argc = 0; argc < NUM_ARGV; ++argc)
6757 argv[argc] = 0;
6758
6759 argc = 0;
6760 argv[argc++] = initial_argv[0];
6761
6762 if (strlen (dpy_name) != 0)
6763 {
6764 argv[argc++] = display_opt;
6765 argv[argc++] = dpy_name;
6766 }
6767
6768 argv[argc++] = name_opt;
6769 argv[argc++] = resource_name;
6770
6771
6772
6773 id = g_log_set_handler ("GLib", G_LOG_LEVEL_WARNING | G_LOG_FLAG_FATAL
6774 | G_LOG_FLAG_RECURSION, my_log_handler, NULL);
6775
6776
6777 fixup_locale ();
6778 unrequest_sigio ();
6779 gtk_init (&argc, &argv2);
6780 request_sigio ();
6781 fixup_locale ();
6782
6783
6784 g_log_remove_handler ("GLib", id);
6785
6786 xg_initialize ();
6787
6788 dpy = DEFAULT_GDK_DISPLAY ();
6789
6790 initial_display = g_strdup (gdk_display_get_name (dpy));
6791 dpy_name = initial_display;
6792 lisp_dpy_name = build_string (dpy_name);
6793 }
6794 }
6795
6796
6797 if (dpy == 0)
6798 {
6799 unblock_input ();
6800 return 0;
6801 }
6802
6803
6804
6805 pgtk_display_x_warning (dpy);
6806
6807 dpyinfo = xzalloc (sizeof *dpyinfo);
6808 pgtk_initialize_display_info (dpyinfo);
6809 terminal = pgtk_create_terminal (dpyinfo);
6810
6811 {
6812 struct pgtk_display_info *share;
6813
6814 for (share = x_display_list; share; share = share->next)
6815 if (same_x_server (SSDATA (XCAR (share->name_list_element)), dpy_name))
6816 break;
6817 if (share)
6818 terminal->kboard = share->terminal->kboard;
6819 else
6820 {
6821 terminal->kboard = allocate_kboard (Qpgtk);
6822
6823
6824
6825
6826 if (current_kboard == initial_kboard)
6827 current_kboard = terminal->kboard;
6828 }
6829 terminal->kboard->reference_count++;
6830 }
6831
6832
6833 dpyinfo->next = x_display_list;
6834 x_display_list = dpyinfo;
6835
6836 dpyinfo->name_list_element = Fcons (lisp_dpy_name, Qnil);
6837 dpyinfo->gdpy = dpy;
6838
6839
6840 dpyinfo->smallest_font_height = 1;
6841 dpyinfo->smallest_char_width = 1;
6842
6843
6844 terminal->name = xlispstrdup (lisp_dpy_name);
6845
6846 Lisp_Object system_name = Fsystem_name ();
6847 ptrdiff_t nbytes;
6848 if (INT_ADD_WRAPV (SBYTES (Vinvocation_name), SBYTES (system_name) + 2,
6849 &nbytes))
6850 memory_full (SIZE_MAX);
6851 dpyinfo->x_id = ++x_display_id;
6852 dpyinfo->x_id_name = xmalloc (nbytes);
6853 char *nametail = lispstpcpy (dpyinfo->x_id_name, Vinvocation_name);
6854 *nametail++ = '@';
6855 lispstpcpy (nametail, system_name);
6856
6857
6858
6859 dpyinfo->xg_cursor = xg_create_default_cursor (dpyinfo->gdpy);
6860
6861 dpyinfo->vertical_scroll_bar_cursor
6862 = gdk_cursor_new_for_display (dpyinfo->gdpy, GDK_SB_V_DOUBLE_ARROW);
6863
6864 dpyinfo->horizontal_scroll_bar_cursor
6865 = gdk_cursor_new_for_display (dpyinfo->gdpy, GDK_SB_H_DOUBLE_ARROW);
6866
6867 dpyinfo->icon_bitmap_id = -1;
6868
6869 reset_mouse_highlight (&dpyinfo->mouse_highlight);
6870
6871 gscr = gdk_display_get_default_screen (dpyinfo->gdpy);
6872 dpi = gdk_screen_get_resolution (gscr);
6873
6874 if (dpi < 0)
6875 dpi = 96.0;
6876
6877 dpyinfo->resx = dpi;
6878 dpyinfo->resy = dpi;
6879
6880 g_signal_connect (G_OBJECT (gscr), "monitors-changed",
6881 G_CALLBACK (pgtk_monitors_changed_cb),
6882 terminal);
6883
6884
6885 dpyinfo->scroll.x_per_char = 1;
6886 dpyinfo->scroll.y_per_line = 1;
6887
6888 dpyinfo->connection = -1;
6889
6890 if (!handle)
6891 handle = dlopen (NULL, RTLD_LAZY);
6892
6893 #ifdef GDK_WINDOWING_X11
6894 if (!strcmp (G_OBJECT_TYPE_NAME (dpy), "GdkX11Display") && handle)
6895 {
6896 void *(*gdk_x11_display_get_xdisplay) (GdkDisplay *)
6897 = dlsym (handle, "gdk_x11_display_get_xdisplay");
6898 int (*x_connection_number) (void *)
6899 = dlsym (handle, "XConnectionNumber");
6900
6901 if (x_connection_number
6902 && gdk_x11_display_get_xdisplay)
6903 dpyinfo->connection
6904 = x_connection_number (gdk_x11_display_get_xdisplay (dpy));
6905 }
6906 #endif
6907
6908 #ifdef GDK_WINDOWING_WAYLAND
6909 if (GDK_IS_WAYLAND_DISPLAY (dpy) && handle)
6910 {
6911 struct wl_display *wl_dpy = gdk_wayland_display_get_wl_display (dpy);
6912 int (*display_get_fd) (struct wl_display *)
6913 = dlsym (handle, "wl_display_get_fd");
6914
6915 if (display_get_fd)
6916 dpyinfo->connection = display_get_fd (wl_dpy);
6917 }
6918 #endif
6919
6920 if (dpyinfo->connection >= 0)
6921 {
6922 add_keyboard_wait_descriptor (dpyinfo->connection);
6923 #ifdef F_SETOWN
6924 fcntl (dpyinfo->connection, F_SETOWN, getpid ());
6925 #endif
6926
6927 if (interrupt_input)
6928 init_sigio (dpyinfo->connection);
6929 }
6930
6931 dpyinfo->invisible_cursor
6932 = gdk_cursor_new_for_display (dpyinfo->gdpy, GDK_BLANK_CURSOR);
6933
6934 xsettings_initialize (dpyinfo);
6935
6936 pgtk_im_init (dpyinfo);
6937
6938 g_signal_connect (G_OBJECT (dpyinfo->gdpy), "seat-added",
6939 G_CALLBACK (pgtk_seat_added_cb), dpyinfo);
6940 g_signal_connect (G_OBJECT (dpyinfo->gdpy), "seat-removed",
6941 G_CALLBACK (pgtk_seat_removed_cb), dpyinfo);
6942 pgtk_enumerate_devices (dpyinfo, true);
6943
6944 unblock_input ();
6945
6946 return dpyinfo;
6947 }
6948
6949
6950
6951
6952 static void
6953 pgtk_delete_display (struct pgtk_display_info *dpyinfo)
6954 {
6955 struct terminal *t;
6956
6957
6958
6959 for (t = terminal_list; t; t = t->next_terminal)
6960 if (t->type == output_pgtk && t->display_info.pgtk == dpyinfo)
6961 {
6962 delete_terminal (t);
6963 break;
6964 }
6965
6966 if (x_display_list == dpyinfo)
6967 x_display_list = dpyinfo->next;
6968 else
6969 {
6970 struct pgtk_display_info *tail;
6971
6972 for (tail = x_display_list; tail; tail = tail->next)
6973 if (tail->next == dpyinfo)
6974 tail->next = tail->next->next;
6975 }
6976
6977 pgtk_free_devices (dpyinfo);
6978 xfree (dpyinfo);
6979 }
6980
6981 char *
6982 pgtk_xlfd_to_fontname (const char *xlfd)
6983
6984
6985
6986
6987
6988 {
6989 char *name = xmalloc (180);
6990
6991 if (!strncmp (xlfd, "--", 2))
6992 {
6993 if (sscanf (xlfd, "--%179[^-]-", name) != 1)
6994 name[0] = '\0';
6995 }
6996 else
6997 {
6998 if (sscanf (xlfd, "-%*[^-]-%179[^-]-", name) != 1)
6999 name[0] = '\0';
7000 }
7001
7002
7003 if (strlen (name) == 0)
7004 strcpy (name, "Monospace");
7005
7006 return name;
7007 }
7008
7009 bool
7010 pgtk_defined_color (struct frame *f, const char *name,
7011 Emacs_Color *color_def, bool alloc,
7012 bool makeIndex)
7013
7014
7015
7016
7017
7018
7019
7020 {
7021 int r;
7022
7023 block_input ();
7024 r = xg_check_special_colors (f, name, color_def);
7025 if (!r)
7026 r = pgtk_parse_color (f, name, color_def);
7027 unblock_input ();
7028 return r;
7029 }
7030
7031
7032
7033
7034
7035
7036
7037
7038
7039 int
7040 pgtk_parse_color (struct frame *f, const char *color_name,
7041 Emacs_Color * color)
7042 {
7043 GdkRGBA rgba;
7044 if (gdk_rgba_parse (&rgba, color_name))
7045 {
7046 color->red = rgba.red * 65535;
7047 color->green = rgba.green * 65535;
7048 color->blue = rgba.blue * 65535;
7049 color->pixel = ((color->red >> 8) << 16
7050 | (color->green >> 8) << 8
7051 | (color->blue >> 8) << 0);
7052 return 1;
7053 }
7054 return 0;
7055 }
7056
7057
7058
7059
7060 void
7061 pgtk_query_colors (struct frame *f, Emacs_Color * colors, int ncolors)
7062 {
7063 int i;
7064
7065 for (i = 0; i < ncolors; i++)
7066 {
7067 unsigned long pixel = colors[i].pixel;
7068
7069 #define GetRValue(p) (((p) >> 16) & 0xff)
7070 #define GetGValue(p) (((p) >> 8) & 0xff)
7071 #define GetBValue(p) (((p) >> 0) & 0xff)
7072 colors[i].red = GetRValue (pixel) * 257;
7073 colors[i].green = GetGValue (pixel) * 257;
7074 colors[i].blue = GetBValue (pixel) * 257;
7075 }
7076 }
7077
7078 void
7079 pgtk_query_color (struct frame *f, Emacs_Color * color)
7080 {
7081 pgtk_query_colors (f, color, 1);
7082 }
7083
7084 void
7085 pgtk_clear_area (struct frame *f, int x, int y, int width, int height)
7086 {
7087 cairo_t *cr;
7088
7089 eassert (width > 0 && height > 0);
7090
7091 cr = pgtk_begin_cr_clip (f);
7092 pgtk_set_cr_source_with_color (f, FRAME_X_OUTPUT (f)->background_color,
7093 true);
7094 cairo_rectangle (cr, x, y, width, height);
7095 cairo_fill (cr);
7096 pgtk_end_cr_clip (f);
7097 }
7098
7099
7100 void
7101 syms_of_pgtkterm (void)
7102 {
7103 DEFSYM (Qmodifier_value, "modifier-value");
7104 DEFSYM (Qalt, "alt");
7105 DEFSYM (Qhyper, "hyper");
7106 DEFSYM (Qmeta, "meta");
7107 DEFSYM (Qsuper, "super");
7108 DEFSYM (Qcontrol, "control");
7109 DEFSYM (QUTF8_STRING, "UTF8_STRING");
7110
7111 DEFSYM (Qfile, "file");
7112 DEFSYM (Qurl, "url");
7113
7114 DEFSYM (Qlatin_1, "latin-1");
7115
7116 xg_default_icon_file
7117 = build_pure_c_string ("icons/hicolor/scalable/apps/emacs.svg");
7118 staticpro (&xg_default_icon_file);
7119
7120 DEFSYM (Qx_gtk_map_stock, "x-gtk-map-stock");
7121
7122 DEFSYM (Qcopy, "copy");
7123 DEFSYM (Qmove, "move");
7124 DEFSYM (Qlink, "link");
7125 DEFSYM (Qprivate, "private");
7126
7127
7128 Fput (Qalt, Qmodifier_value, make_fixnum (alt_modifier));
7129 Fput (Qhyper, Qmodifier_value, make_fixnum (hyper_modifier));
7130 Fput (Qmeta, Qmodifier_value, make_fixnum (meta_modifier));
7131 Fput (Qsuper, Qmodifier_value, make_fixnum (super_modifier));
7132 Fput (Qcontrol, Qmodifier_value, make_fixnum (ctrl_modifier));
7133
7134 DEFVAR_LISP ("x-ctrl-keysym", Vx_ctrl_keysym,
7135 doc: );
7136 Vx_ctrl_keysym = Qnil;
7137
7138 DEFVAR_LISP ("x-alt-keysym", Vx_alt_keysym,
7139 doc: );
7140 Vx_alt_keysym = Qnil;
7141
7142 DEFVAR_LISP ("x-hyper-keysym", Vx_hyper_keysym,
7143 doc: );
7144 Vx_hyper_keysym = Qnil;
7145
7146 DEFVAR_LISP ("x-meta-keysym", Vx_meta_keysym,
7147 doc: );
7148 Vx_meta_keysym = Qnil;
7149
7150 DEFVAR_LISP ("x-super-keysym", Vx_super_keysym,
7151 doc: );
7152 Vx_super_keysym = Qnil;
7153
7154 DEFVAR_BOOL ("x-use-underline-position-properties",
7155 x_use_underline_position_properties,
7156 doc: );
7157 x_use_underline_position_properties = 1;
7158
7159 DEFVAR_BOOL ("x-underline-at-descent-line",
7160 x_underline_at_descent_line,
7161 doc: );
7162 x_underline_at_descent_line = 0;
7163
7164 DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
7165 doc: );
7166 Vx_toolkit_scroll_bars = intern_c_string ("gtk");
7167
7168 DEFVAR_LISP ("pgtk-wait-for-event-timeout", Vpgtk_wait_for_event_timeout,
7169 doc:
7170
7171
7172
7173
7174
7175
7176 );
7177 Vpgtk_wait_for_event_timeout = make_float (0.1);
7178
7179 DEFVAR_LISP ("pgtk-keysym-table", Vpgtk_keysym_table,
7180 doc: );
7181 Vpgtk_keysym_table = make_hash_table (hashtest_eql, 900, DEFAULT_REHASH_SIZE,
7182 DEFAULT_REHASH_THRESHOLD, Qnil, false);
7183
7184 window_being_scrolled = Qnil;
7185 staticpro (&window_being_scrolled);
7186
7187
7188 Fprovide (Qpgtk, Qnil);
7189 }
7190
7191
7192
7193
7194
7195
7196
7197
7198 void
7199 pgtk_cr_update_surface_desired_size (struct frame *f, int width, int height, bool force)
7200 {
7201 if (FRAME_CR_SURFACE_DESIRED_WIDTH (f) != width
7202 || FRAME_CR_SURFACE_DESIRED_HEIGHT (f) != height
7203 || force)
7204 {
7205 pgtk_cr_destroy_frame_context (f);
7206 FRAME_CR_SURFACE_DESIRED_WIDTH (f) = width;
7207 FRAME_CR_SURFACE_DESIRED_HEIGHT (f) = height;
7208 SET_FRAME_GARBAGED (f);
7209 }
7210 }
7211
7212
7213 cairo_t *
7214 pgtk_begin_cr_clip (struct frame *f)
7215 {
7216 cairo_t *cr = FRAME_CR_CONTEXT (f);
7217
7218 if (!cr)
7219 {
7220 cairo_surface_t *surface
7221 = gdk_window_create_similar_surface (gtk_widget_get_window
7222 (FRAME_GTK_WIDGET (f)),
7223 CAIRO_CONTENT_COLOR_ALPHA,
7224 FRAME_CR_SURFACE_DESIRED_WIDTH (f),
7225 FRAME_CR_SURFACE_DESIRED_HEIGHT
7226 (f));
7227
7228 cr = FRAME_CR_CONTEXT (f) = cairo_create (surface);
7229 cairo_surface_destroy (surface);
7230 }
7231
7232 cairo_save (cr);
7233
7234 return cr;
7235 }
7236
7237 void
7238 pgtk_end_cr_clip (struct frame *f)
7239 {
7240 cairo_restore (FRAME_CR_CONTEXT (f));
7241 }
7242
7243 void
7244 pgtk_set_cr_source_with_gc_foreground (struct frame *f, Emacs_GC *gc,
7245 bool respects_alpha_background)
7246 {
7247 pgtk_set_cr_source_with_color (f, gc->foreground,
7248 respects_alpha_background);
7249 }
7250
7251 void
7252 pgtk_set_cr_source_with_gc_background (struct frame *f, Emacs_GC *gc,
7253 bool respects_alpha_background)
7254 {
7255 pgtk_set_cr_source_with_color (f, gc->background,
7256 respects_alpha_background);
7257 }
7258
7259 void
7260 pgtk_set_cr_source_with_color (struct frame *f, unsigned long color,
7261 bool respects_alpha_background)
7262 {
7263 Emacs_Color col;
7264 col.pixel = color;
7265 pgtk_query_color (f, &col);
7266
7267 if (!respects_alpha_background)
7268 {
7269 cairo_set_source_rgb (FRAME_CR_CONTEXT (f), col.red / 65535.0,
7270 col.green / 65535.0, col.blue / 65535.0);
7271 cairo_set_operator (FRAME_CR_CONTEXT (f), CAIRO_OPERATOR_OVER);
7272 }
7273 else
7274 {
7275 cairo_set_source_rgba (FRAME_CR_CONTEXT (f), col.red / 65535.0,
7276 col.green / 65535.0, col.blue / 65535.0,
7277 f->alpha_background);
7278 cairo_set_operator (FRAME_CR_CONTEXT (f), CAIRO_OPERATOR_SOURCE);
7279 }
7280 }
7281
7282 void
7283 pgtk_cr_draw_frame (cairo_t * cr, struct frame *f)
7284 {
7285 cairo_set_source_surface (cr, FRAME_CR_SURFACE (f), 0, 0);
7286 cairo_paint (cr);
7287 }
7288
7289 static cairo_status_t
7290 pgtk_cr_accumulate_data (void *closure, const unsigned char *data,
7291 unsigned int length)
7292 {
7293 Lisp_Object *acc = (Lisp_Object *) closure;
7294
7295 *acc = Fcons (make_unibyte_string ((char const *) data, length), *acc);
7296
7297 return CAIRO_STATUS_SUCCESS;
7298 }
7299
7300 void
7301 pgtk_cr_destroy_frame_context (struct frame *f)
7302 {
7303 if (FRAME_CR_CONTEXT (f) != NULL)
7304 {
7305 cairo_destroy (FRAME_CR_CONTEXT (f));
7306 FRAME_CR_CONTEXT (f) = NULL;
7307 }
7308 }
7309
7310 static void
7311 pgtk_cr_destroy (void *cr)
7312 {
7313 block_input ();
7314 cairo_destroy (cr);
7315 unblock_input ();
7316 }
7317
7318 Lisp_Object
7319 pgtk_cr_export_frames (Lisp_Object frames, cairo_surface_type_t surface_type)
7320 {
7321 struct frame *f;
7322 cairo_surface_t *surface;
7323 cairo_t *cr;
7324 int width, height;
7325 void (*surface_set_size_func) (cairo_surface_t *, double, double) = NULL;
7326 Lisp_Object acc = Qnil;
7327 specpdl_ref count = SPECPDL_INDEX ();
7328
7329 specbind (Qredisplay_dont_pause, Qt);
7330 redisplay_preserve_echo_area (31);
7331
7332 f = XFRAME (XCAR (frames));
7333 frames = XCDR (frames);
7334 width = FRAME_PIXEL_WIDTH (f);
7335 height = FRAME_PIXEL_HEIGHT (f);
7336
7337 block_input ();
7338 #ifdef CAIRO_HAS_PDF_SURFACE
7339 if (surface_type == CAIRO_SURFACE_TYPE_PDF)
7340 {
7341 surface = cairo_pdf_surface_create_for_stream (pgtk_cr_accumulate_data, &acc,
7342 width, height);
7343 surface_set_size_func = cairo_pdf_surface_set_size;
7344 }
7345 else
7346 #endif
7347 #ifdef CAIRO_HAS_PNG_FUNCTIONS
7348 if (surface_type == CAIRO_SURFACE_TYPE_IMAGE)
7349 surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, width, height);
7350 else
7351 #endif
7352 #ifdef CAIRO_HAS_PS_SURFACE
7353 if (surface_type == CAIRO_SURFACE_TYPE_PS)
7354 {
7355 surface = cairo_ps_surface_create_for_stream (pgtk_cr_accumulate_data, &acc,
7356 width, height);
7357 surface_set_size_func = cairo_ps_surface_set_size;
7358 }
7359 else
7360 #endif
7361 #ifdef CAIRO_HAS_SVG_SURFACE
7362 if (surface_type == CAIRO_SURFACE_TYPE_SVG)
7363 surface = cairo_svg_surface_create_for_stream (pgtk_cr_accumulate_data, &acc,
7364 width, height);
7365 else
7366 #endif
7367 abort ();
7368
7369 cr = cairo_create (surface);
7370 cairo_surface_destroy (surface);
7371 record_unwind_protect_ptr (pgtk_cr_destroy, cr);
7372
7373 while (1)
7374 {
7375 cairo_t *saved_cr = FRAME_CR_CONTEXT (f);
7376 FRAME_CR_CONTEXT (f) = cr;
7377 pgtk_clear_area (f, 0, 0, width, height);
7378 expose_frame (f, 0, 0, width, height);
7379 FRAME_CR_CONTEXT (f) = saved_cr;
7380
7381 if (NILP (frames))
7382 break;
7383
7384 cairo_surface_show_page (surface);
7385 f = XFRAME (XCAR (frames));
7386 frames = XCDR (frames);
7387 width = FRAME_PIXEL_WIDTH (f);
7388 height = FRAME_PIXEL_HEIGHT (f);
7389 if (surface_set_size_func)
7390 (*surface_set_size_func) (surface, width, height);
7391
7392 unblock_input ();
7393 maybe_quit ();
7394 block_input ();
7395 }
7396
7397 #ifdef CAIRO_HAS_PNG_FUNCTIONS
7398 if (surface_type == CAIRO_SURFACE_TYPE_IMAGE)
7399 {
7400 cairo_surface_flush (surface);
7401 cairo_surface_write_to_png_stream (surface, pgtk_cr_accumulate_data, &acc);
7402 }
7403 #endif
7404 unblock_input ();
7405
7406 unbind_to (count, Qnil);
7407
7408 return CALLN (Fapply, intern ("concat"), Fnreverse (acc));
7409 }