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 static bool
3154 pgtk_bitmap_icon (struct frame *f, Lisp_Object file)
3155 {
3156
3157
3158
3159
3160
3161 #if 0
3162 ptrdiff_t bitmap_id;
3163
3164 if (FRAME_GTK_WIDGET (f) == 0)
3165 return true;
3166
3167
3168 if (f->output_data.pgtk->icon_bitmap > 0)
3169 image_destroy_bitmap (f, f->output_data.pgtk->icon_bitmap);
3170 f->output_data.pgtk->icon_bitmap = 0;
3171
3172 if (STRINGP (file))
3173 {
3174
3175
3176 if (xg_set_icon (f, file))
3177 return false;
3178 bitmap_id = image_create_bitmap_from_file (f, file);
3179 }
3180 else
3181 {
3182
3183 if (FRAME_DISPLAY_INFO (f)->icon_bitmap_id < 0)
3184 {
3185 ptrdiff_t rc = -1;
3186
3187 if (xg_set_icon (f, xg_default_icon_file)
3188 || xg_set_icon_from_xpm_data (f, gnu_xpm_bits))
3189 {
3190 FRAME_DISPLAY_INFO (f)->icon_bitmap_id = -2;
3191 return false;
3192 }
3193
3194
3195 if (rc == -1)
3196 {
3197 rc = image_create_bitmap_from_data (f,
3198 (char *) gnu_xbm_bits,
3199 gnu_xbm_width,
3200 gnu_xbm_height);
3201 if (rc == -1)
3202 return true;
3203
3204 FRAME_DISPLAY_INFO (f)->icon_bitmap_id = rc;
3205 }
3206 }
3207
3208
3209
3210
3211
3212 image_reference_bitmap (f, FRAME_DISPLAY_INFO (f)->icon_bitmap_id);
3213
3214 bitmap_id = FRAME_DISPLAY_INFO (f)->icon_bitmap_id;
3215 }
3216
3217 f->output_data.pgtk->icon_bitmap = bitmap_id;
3218 #endif
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 - FRAME_BOTTOM_MARGIN_HEIGHT (f)),
3774 width, flash_height);
3775 cairo_fill (cr);
3776 }
3777 else
3778 {
3779
3780 cairo_rectangle (cr,
3781 flash_left, FRAME_INTERNAL_BORDER_WIDTH (f),
3782 width, height - 2 * FRAME_INTERNAL_BORDER_WIDTH (f));
3783 cairo_fill (cr);
3784 }
3785
3786 FRAME_X_OUTPUT (f)->cr_surface_visible_bell = surface;
3787
3788 delay = make_timespec (0, 50 * 1000 * 1000);
3789
3790 if (FRAME_X_OUTPUT (f)->atimer_visible_bell != NULL)
3791 {
3792 cancel_atimer (FRAME_X_OUTPUT (f)->atimer_visible_bell);
3793 FRAME_X_OUTPUT (f)->atimer_visible_bell = NULL;
3794 }
3795
3796 FRAME_X_OUTPUT (f)->atimer_visible_bell
3797 = start_atimer (ATIMER_RELATIVE, delay, recover_from_visible_bell, f);
3798
3799
3800 cairo_destroy (cr);
3801 unblock_input ();
3802 }
3803
3804
3805
3806 static void
3807 pgtk_ring_bell (struct frame *f)
3808 {
3809 if (visible_bell)
3810 {
3811 pgtk_flash (f);
3812 }
3813 else
3814 {
3815 block_input ();
3816 gtk_widget_error_bell (FRAME_GTK_WIDGET (f));
3817 unblock_input ();
3818 }
3819 }
3820
3821
3822
3823
3824
3825
3826
3827
3828
3829 static int
3830 pgtk_read_socket (struct terminal *terminal, struct input_event *hold_quit)
3831 {
3832 GMainContext *context;
3833 bool context_acquired = false;
3834 int count;
3835
3836 count = evq_flush (hold_quit);
3837 if (count > 0)
3838 {
3839 return count;
3840 }
3841
3842 context = g_main_context_default ();
3843 context_acquired = g_main_context_acquire (context);
3844
3845 block_input ();
3846
3847 if (context_acquired)
3848 {
3849 while (g_main_context_pending (context))
3850 {
3851 g_main_context_dispatch (context);
3852 }
3853 }
3854
3855 unblock_input ();
3856
3857 if (context_acquired)
3858 g_main_context_release (context);
3859
3860 count = evq_flush (hold_quit);
3861 if (count > 0)
3862 {
3863 return count;
3864 }
3865
3866 return 0;
3867 }
3868
3869
3870
3871
3872 static Lisp_Object window_being_scrolled;
3873
3874 static void
3875 pgtk_send_scroll_bar_event (Lisp_Object window, enum scroll_bar_part part,
3876 int portion, int whole, bool horizontal)
3877 {
3878 union buffered_input_event inev;
3879
3880 EVENT_INIT (inev.ie);
3881
3882 inev.ie.kind = (horizontal
3883 ? HORIZONTAL_SCROLL_BAR_CLICK_EVENT
3884 : SCROLL_BAR_CLICK_EVENT);
3885 inev.ie.frame_or_window = window;
3886 inev.ie.arg = Qnil;
3887 inev.ie.timestamp = 0;
3888 inev.ie.code = 0;
3889 inev.ie.part = part;
3890 inev.ie.x = make_fixnum (portion);
3891 inev.ie.y = make_fixnum (whole);
3892 inev.ie.modifiers = 0;
3893
3894 evq_enqueue (&inev);
3895 }
3896
3897
3898
3899
3900
3901 static gboolean
3902 xg_scroll_callback (GtkRange * range,
3903 GtkScrollType scroll, gdouble value, gpointer user_data)
3904 {
3905 int whole = 0, portion = 0;
3906 struct scroll_bar *bar = user_data;
3907 enum scroll_bar_part part = scroll_bar_nowhere;
3908 GtkAdjustment *adj = GTK_ADJUSTMENT (gtk_range_get_adjustment (range));
3909
3910 if (xg_ignore_gtk_scrollbar)
3911 return false;
3912
3913 switch (scroll)
3914 {
3915 case GTK_SCROLL_JUMP:
3916 if (bar->horizontal)
3917 {
3918 part = scroll_bar_horizontal_handle;
3919 whole = (int) (gtk_adjustment_get_upper (adj) -
3920 gtk_adjustment_get_page_size (adj));
3921 portion = min ((int) value, whole);
3922 bar->dragging = portion;
3923 }
3924 else
3925 {
3926 part = scroll_bar_handle;
3927 whole = gtk_adjustment_get_upper (adj) -
3928 gtk_adjustment_get_page_size (adj);
3929 portion = min ((int) value, whole);
3930 bar->dragging = portion;
3931 }
3932 break;
3933 case GTK_SCROLL_STEP_BACKWARD:
3934 part = (bar->horizontal ? scroll_bar_left_arrow : scroll_bar_up_arrow);
3935 bar->dragging = -1;
3936 break;
3937 case GTK_SCROLL_STEP_FORWARD:
3938 part = (bar->horizontal
3939 ? scroll_bar_right_arrow : scroll_bar_down_arrow);
3940 bar->dragging = -1;
3941 break;
3942 case GTK_SCROLL_PAGE_BACKWARD:
3943 part = (bar->horizontal
3944 ? scroll_bar_before_handle : scroll_bar_above_handle);
3945 bar->dragging = -1;
3946 break;
3947 case GTK_SCROLL_PAGE_FORWARD:
3948 part = (bar->horizontal
3949 ? scroll_bar_after_handle : scroll_bar_below_handle);
3950 bar->dragging = -1;
3951 break;
3952 default:
3953 break;
3954 }
3955
3956 if (part != scroll_bar_nowhere)
3957 {
3958 window_being_scrolled = bar->window;
3959 pgtk_send_scroll_bar_event (bar->window, part, portion, whole,
3960 bar->horizontal);
3961 }
3962
3963 return false;
3964 }
3965
3966
3967
3968 static gboolean
3969 xg_end_scroll_callback (GtkWidget * widget,
3970 GdkEventButton * event, gpointer user_data)
3971 {
3972 struct scroll_bar *bar = user_data;
3973 bar->dragging = -1;
3974 if (WINDOWP (window_being_scrolled))
3975 {
3976 pgtk_send_scroll_bar_event (window_being_scrolled,
3977 scroll_bar_end_scroll, 0, 0,
3978 bar->horizontal);
3979 window_being_scrolled = Qnil;
3980 }
3981
3982 return false;
3983 }
3984
3985 #define SCROLL_BAR_NAME "verticalScrollBar"
3986 #define SCROLL_BAR_HORIZONTAL_NAME "horizontalScrollBar"
3987
3988
3989
3990
3991 static void
3992 pgtk_create_toolkit_scroll_bar (struct frame *f, struct scroll_bar *bar)
3993 {
3994 const char *scroll_bar_name = SCROLL_BAR_NAME;
3995
3996 block_input ();
3997 xg_create_scroll_bar (f, bar, G_CALLBACK (xg_scroll_callback),
3998 G_CALLBACK (xg_end_scroll_callback), scroll_bar_name);
3999 unblock_input ();
4000 }
4001
4002 static void
4003 pgtk_create_horizontal_toolkit_scroll_bar (struct frame *f,
4004 struct scroll_bar *bar)
4005 {
4006 const char *scroll_bar_name = SCROLL_BAR_HORIZONTAL_NAME;
4007
4008 block_input ();
4009 xg_create_horizontal_scroll_bar (f, bar, G_CALLBACK (xg_scroll_callback),
4010 G_CALLBACK (xg_end_scroll_callback),
4011 scroll_bar_name);
4012 unblock_input ();
4013 }
4014
4015
4016
4017
4018 static void
4019 pgtk_set_toolkit_scroll_bar_thumb (struct scroll_bar *bar, int portion,
4020 int position, int whole)
4021 {
4022 xg_set_toolkit_scroll_bar_thumb (bar, portion, position, whole);
4023 }
4024
4025 static void
4026 pgtk_set_toolkit_horizontal_scroll_bar_thumb (struct scroll_bar *bar,
4027 int portion, int position,
4028 int whole)
4029 {
4030 xg_set_toolkit_horizontal_scroll_bar_thumb (bar, portion, position, whole);
4031 }
4032
4033
4034
4035
4036
4037
4038 static struct scroll_bar *
4039 pgtk_scroll_bar_create (struct window *w, int top, int left,
4040 int width, int height, bool horizontal)
4041 {
4042 struct frame *f = XFRAME (w->frame);
4043 struct scroll_bar *bar
4044 = ALLOCATE_PSEUDOVECTOR (struct scroll_bar, prev, PVEC_OTHER);
4045 Lisp_Object barobj;
4046
4047 block_input ();
4048
4049 if (horizontal)
4050 pgtk_create_horizontal_toolkit_scroll_bar (f, bar);
4051 else
4052 pgtk_create_toolkit_scroll_bar (f, bar);
4053
4054 XSETWINDOW (bar->window, w);
4055 bar->top = top;
4056 bar->left = left;
4057 bar->width = width;
4058 bar->height = height;
4059 bar->start = 0;
4060 bar->end = 0;
4061 bar->dragging = -1;
4062 bar->horizontal = horizontal;
4063
4064
4065 bar->next = FRAME_SCROLL_BARS (f);
4066 bar->prev = Qnil;
4067 XSETVECTOR (barobj, bar);
4068 fset_scroll_bars (f, barobj);
4069 if (!NILP (bar->next))
4070 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
4071
4072
4073 {
4074 if (horizontal)
4075 xg_update_horizontal_scrollbar_pos (f, bar->x_window, top,
4076 left, width, max (height, 1));
4077 else
4078 xg_update_scrollbar_pos (f, bar->x_window, top,
4079 left, width, max (height, 1));
4080 }
4081
4082 unblock_input ();
4083 return bar;
4084 }
4085
4086
4087
4088
4089 static void
4090 pgtk_scroll_bar_remove (struct scroll_bar *bar)
4091 {
4092 struct frame *f = XFRAME (WINDOW_FRAME (XWINDOW (bar->window)));
4093 block_input ();
4094
4095 xg_remove_scroll_bar (f, bar->x_window);
4096
4097
4098 if (bar->horizontal)
4099 wset_horizontal_scroll_bar (XWINDOW (bar->window), Qnil);
4100 else
4101 wset_vertical_scroll_bar (XWINDOW (bar->window), Qnil);
4102
4103 unblock_input ();
4104 }
4105
4106
4107
4108
4109
4110
4111 static void
4112 pgtk_set_vertical_scroll_bar (struct window *w, int portion, int whole,
4113 int position)
4114 {
4115 struct frame *f = XFRAME (w->frame);
4116 Lisp_Object barobj;
4117 struct scroll_bar *bar;
4118 int top, height, left, width;
4119 int window_y, window_height;
4120
4121
4122 window_box (w, ANY_AREA, 0, &window_y, 0, &window_height);
4123 top = window_y;
4124 height = window_height;
4125 left = WINDOW_SCROLL_BAR_AREA_X (w);
4126 width = WINDOW_SCROLL_BAR_AREA_WIDTH (w);
4127
4128
4129 if (NILP (w->vertical_scroll_bar))
4130 {
4131 if (width > 0 && height > 0)
4132 {
4133 block_input ();
4134 pgtk_clear_area (f, left, top, width, height);
4135 unblock_input ();
4136 }
4137
4138 bar = pgtk_scroll_bar_create (w, top, left, width, max (height, 1), false);
4139 }
4140 else
4141 {
4142
4143 unsigned int mask = 0;
4144
4145 bar = XSCROLL_BAR (w->vertical_scroll_bar);
4146
4147 block_input ();
4148
4149 if (left != bar->left)
4150 mask |= 1;
4151 if (top != bar->top)
4152 mask |= 1;
4153 if (width != bar->width)
4154 mask |= 1;
4155 if (height != bar->height)
4156 mask |= 1;
4157
4158
4159 if (mask)
4160 {
4161
4162
4163 if (width > 0 && height > 0)
4164 pgtk_clear_area (f, left, top, width, height);
4165 xg_update_scrollbar_pos (f, bar->x_window, top,
4166 left, width, max (height, 1));
4167 }
4168
4169
4170 bar->left = left;
4171 bar->top = top;
4172 bar->width = width;
4173 bar->height = height;
4174
4175 unblock_input ();
4176 }
4177
4178 pgtk_set_toolkit_scroll_bar_thumb (bar, portion, position, whole);
4179
4180 XSETVECTOR (barobj, bar);
4181 wset_vertical_scroll_bar (w, barobj);
4182 }
4183
4184 static void
4185 pgtk_set_horizontal_scroll_bar (struct window *w, int portion, int whole,
4186 int position)
4187 {
4188 struct frame *f = XFRAME (w->frame);
4189 Lisp_Object barobj;
4190 struct scroll_bar *bar;
4191 int top, height, left, width;
4192 int window_x, window_width;
4193 int pixel_width = WINDOW_PIXEL_WIDTH (w);
4194
4195
4196 window_box (w, ANY_AREA, &window_x, 0, &window_width, 0);
4197 left = window_x;
4198 width = window_width;
4199 top = WINDOW_SCROLL_BAR_AREA_Y (w);
4200 height = WINDOW_SCROLL_BAR_AREA_HEIGHT (w);
4201
4202
4203 if (NILP (w->horizontal_scroll_bar))
4204 {
4205 if (width > 0 && height > 0)
4206 {
4207 block_input ();
4208
4209
4210
4211 pgtk_clear_area (f, left, top, pixel_width, height);
4212 unblock_input ();
4213 }
4214
4215 bar = pgtk_scroll_bar_create (w, top, left, width, height, true);
4216 }
4217 else
4218 {
4219
4220 unsigned int mask = 0;
4221
4222 bar = XSCROLL_BAR (w->horizontal_scroll_bar);
4223
4224 block_input ();
4225
4226 if (left != bar->left)
4227 mask |= 1;
4228 if (top != bar->top)
4229 mask |= 1;
4230 if (width != bar->width)
4231 mask |= 1;
4232 if (height != bar->height)
4233 mask |= 1;
4234
4235
4236 if (mask)
4237 {
4238
4239
4240 if (width > 0 && height > 0)
4241 pgtk_clear_area (f,
4242 WINDOW_LEFT_EDGE_X (w), top,
4243 pixel_width - WINDOW_RIGHT_DIVIDER_WIDTH (w),
4244 height);
4245 xg_update_horizontal_scrollbar_pos (f, bar->x_window, top, left,
4246 width, height);
4247 }
4248
4249
4250 bar->left = left;
4251 bar->top = top;
4252 bar->width = width;
4253 bar->height = height;
4254
4255 unblock_input ();
4256 }
4257
4258 pgtk_set_toolkit_horizontal_scroll_bar_thumb (bar, portion, position, whole);
4259
4260 XSETVECTOR (barobj, bar);
4261 wset_horizontal_scroll_bar (w, barobj);
4262 }
4263
4264
4265
4266
4267
4268
4269
4270
4271
4272
4273
4274
4275
4276 static void
4277 pgtk_condemn_scroll_bars (struct frame *frame)
4278 {
4279 if (!NILP (FRAME_SCROLL_BARS (frame)))
4280 {
4281 if (!NILP (FRAME_CONDEMNED_SCROLL_BARS (frame)))
4282 {
4283
4284 Lisp_Object last = FRAME_SCROLL_BARS (frame);
4285
4286 while (!NILP (XSCROLL_BAR (last)->next))
4287 last = XSCROLL_BAR (last)->next;
4288
4289 XSCROLL_BAR (last)->next = FRAME_CONDEMNED_SCROLL_BARS (frame);
4290 XSCROLL_BAR (FRAME_CONDEMNED_SCROLL_BARS (frame))->prev = last;
4291 }
4292
4293 fset_condemned_scroll_bars (frame, FRAME_SCROLL_BARS (frame));
4294 fset_scroll_bars (frame, Qnil);
4295 }
4296 }
4297
4298
4299
4300
4301 static void
4302 pgtk_redeem_scroll_bar (struct window *w)
4303 {
4304 struct scroll_bar *bar;
4305 Lisp_Object barobj;
4306 struct frame *f;
4307
4308
4309 if (NILP (w->vertical_scroll_bar) && NILP (w->horizontal_scroll_bar))
4310 emacs_abort ();
4311
4312 if (!NILP (w->vertical_scroll_bar) && WINDOW_HAS_VERTICAL_SCROLL_BAR (w))
4313 {
4314 bar = XSCROLL_BAR (w->vertical_scroll_bar);
4315
4316 f = XFRAME (WINDOW_FRAME (w));
4317 if (NILP (bar->prev))
4318 {
4319
4320
4321 if (EQ (FRAME_SCROLL_BARS (f), w->vertical_scroll_bar))
4322
4323 goto horizontal;
4324 else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f),
4325 w->vertical_scroll_bar))
4326 fset_condemned_scroll_bars (f, bar->next);
4327 else
4328
4329
4330 emacs_abort ();
4331 }
4332 else
4333 XSCROLL_BAR (bar->prev)->next = bar->next;
4334
4335 if (!NILP (bar->next))
4336 XSCROLL_BAR (bar->next)->prev = bar->prev;
4337
4338 bar->next = FRAME_SCROLL_BARS (f);
4339 bar->prev = Qnil;
4340 XSETVECTOR (barobj, bar);
4341 fset_scroll_bars (f, barobj);
4342 if (!NILP (bar->next))
4343 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
4344 }
4345
4346 horizontal:
4347 if (!NILP (w->horizontal_scroll_bar)
4348 && WINDOW_HAS_HORIZONTAL_SCROLL_BAR (w))
4349 {
4350 bar = XSCROLL_BAR (w->horizontal_scroll_bar);
4351
4352 f = XFRAME (WINDOW_FRAME (w));
4353 if (NILP (bar->prev))
4354 {
4355
4356
4357 if (EQ (FRAME_SCROLL_BARS (f), w->horizontal_scroll_bar))
4358
4359 return;
4360 else if (EQ (FRAME_CONDEMNED_SCROLL_BARS (f),
4361 w->horizontal_scroll_bar))
4362 fset_condemned_scroll_bars (f, bar->next);
4363 else
4364
4365
4366 emacs_abort ();
4367 }
4368 else
4369 XSCROLL_BAR (bar->prev)->next = bar->next;
4370
4371 if (!NILP (bar->next))
4372 XSCROLL_BAR (bar->next)->prev = bar->prev;
4373
4374 bar->next = FRAME_SCROLL_BARS (f);
4375 bar->prev = Qnil;
4376 XSETVECTOR (barobj, bar);
4377 fset_scroll_bars (f, barobj);
4378 if (!NILP (bar->next))
4379 XSETVECTOR (XSCROLL_BAR (bar->next)->prev, bar);
4380 }
4381 }
4382
4383
4384
4385
4386 static void
4387 pgtk_judge_scroll_bars (struct frame *f)
4388 {
4389 Lisp_Object bar, next;
4390
4391 bar = FRAME_CONDEMNED_SCROLL_BARS (f);
4392
4393
4394
4395 fset_condemned_scroll_bars (f, Qnil);
4396
4397 for (; !NILP (bar); bar = next)
4398 {
4399 struct scroll_bar *b = XSCROLL_BAR (bar);
4400
4401 pgtk_scroll_bar_remove (b);
4402
4403 next = b->next;
4404 b->next = b->prev = Qnil;
4405 }
4406
4407
4408
4409 }
4410
4411 static void
4412 set_fullscreen_state (struct frame *f)
4413 {
4414 if (!FRAME_GTK_OUTER_WIDGET (f))
4415 return;
4416
4417 GtkWindow *widget = GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f));
4418 switch (f->want_fullscreen)
4419 {
4420 case FULLSCREEN_NONE:
4421 gtk_window_unfullscreen (widget);
4422 gtk_window_unmaximize (widget);
4423 store_frame_param (f, Qfullscreen, Qnil);
4424 break;
4425
4426 case FULLSCREEN_BOTH:
4427 gtk_window_unmaximize (widget);
4428 gtk_window_fullscreen (widget);
4429 store_frame_param (f, Qfullscreen, Qfullboth);
4430 break;
4431
4432 case FULLSCREEN_MAXIMIZED:
4433 gtk_window_unfullscreen (widget);
4434 gtk_window_maximize (widget);
4435 store_frame_param (f, Qfullscreen, Qmaximized);
4436 break;
4437
4438 case FULLSCREEN_WIDTH:
4439 case FULLSCREEN_HEIGHT:
4440
4441 break;
4442 }
4443
4444 f->want_fullscreen = FULLSCREEN_NONE;
4445 }
4446
4447 static void
4448 pgtk_fullscreen_hook (struct frame *f)
4449 {
4450 if (FRAME_VISIBLE_P (f))
4451 {
4452 block_input ();
4453 set_fullscreen_state (f);
4454 unblock_input ();
4455 }
4456 }
4457
4458
4459 void
4460 pgtk_delete_terminal (struct terminal *terminal)
4461 {
4462 struct pgtk_display_info *dpyinfo = terminal->display_info.pgtk;
4463
4464
4465
4466 if (!terminal->name)
4467 return;
4468
4469 block_input ();
4470
4471 pgtk_im_finish (dpyinfo);
4472
4473
4474 if (dpyinfo->gdpy)
4475 {
4476 image_destroy_all_bitmaps (dpyinfo);
4477
4478 g_clear_object (&dpyinfo->xg_cursor);
4479 g_clear_object (&dpyinfo->vertical_scroll_bar_cursor);
4480 g_clear_object (&dpyinfo->horizontal_scroll_bar_cursor);
4481 g_clear_object (&dpyinfo->invisible_cursor);
4482 if (dpyinfo->last_click_event != NULL)
4483 {
4484 gdk_event_free (dpyinfo->last_click_event);
4485 dpyinfo->last_click_event = NULL;
4486 }
4487
4488
4489
4490 g_signal_handlers_disconnect_by_func (G_OBJECT (dpyinfo->gdpy),
4491 G_CALLBACK (pgtk_seat_added_cb),
4492 dpyinfo);
4493 g_signal_handlers_disconnect_by_func (G_OBJECT (dpyinfo->gdpy),
4494 G_CALLBACK (pgtk_seat_removed_cb),
4495 dpyinfo);
4496 xg_display_close (dpyinfo->gdpy);
4497
4498 dpyinfo->gdpy = NULL;
4499 }
4500
4501 if (dpyinfo->connection >= 0)
4502 emacs_close (dpyinfo->connection);
4503
4504 dpyinfo->connection = -1;
4505
4506 delete_keyboard_wait_descriptor (0);
4507
4508 pgtk_delete_display (dpyinfo);
4509 unblock_input ();
4510 }
4511
4512
4513 static void
4514 pgtk_query_frame_background_color (struct frame *f, Emacs_Color * bgcolor)
4515 {
4516 bgcolor->pixel = FRAME_BACKGROUND_PIXEL (f);
4517 pgtk_query_color (f, bgcolor);
4518 }
4519
4520 static void
4521 pgtk_free_pixmap (struct frame *f, Emacs_Pixmap pixmap)
4522 {
4523 if (pixmap)
4524 {
4525 xfree (pixmap->data);
4526 xfree (pixmap);
4527 }
4528 }
4529
4530 void
4531 pgtk_focus_frame (struct frame *f, bool noactivate)
4532 {
4533 struct pgtk_display_info *dpyinfo;
4534 GtkWidget *widget;
4535 GtkWindow *window;
4536
4537 dpyinfo = FRAME_DISPLAY_INFO (f);
4538
4539 if (FRAME_GTK_OUTER_WIDGET (f) && !noactivate)
4540 {
4541
4542
4543
4544
4545
4546
4547 window = GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f));
4548 gtk_window_present_with_time (window, dpyinfo->last_user_time);
4549 return;
4550 }
4551
4552 widget = FRAME_WIDGET (f);
4553
4554 if (widget)
4555 gtk_widget_grab_focus (widget);
4556 }
4557
4558 static void
4559 set_opacity_recursively (GtkWidget *w, gpointer data)
4560 {
4561 gtk_widget_set_opacity (w, *(double *) data);
4562
4563 if (GTK_IS_CONTAINER (w))
4564 gtk_container_foreach (GTK_CONTAINER (w),
4565 set_opacity_recursively, data);
4566 }
4567
4568 static void
4569 pgtk_set_frame_alpha (struct frame *f)
4570 {
4571 struct pgtk_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
4572 double alpha = 1.0;
4573 double alpha_min = 1.0;
4574
4575 if (dpyinfo->highlight_frame == f)
4576 alpha = f->alpha[0];
4577 else
4578 alpha = f->alpha[1];
4579
4580 if (alpha < 0.0)
4581 return;
4582
4583 if (FLOATP (Vframe_alpha_lower_limit))
4584 alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
4585 else if (FIXNUMP (Vframe_alpha_lower_limit))
4586 alpha_min = (XFIXNUM (Vframe_alpha_lower_limit)) / 100.0;
4587
4588 if (alpha > 1.0)
4589 alpha = 1.0;
4590 else if (alpha < alpha_min && alpha_min <= 1.0)
4591 alpha = alpha_min;
4592
4593 set_opacity_recursively (FRAME_WIDGET (f), &alpha);
4594
4595 gtk_widget_queue_resize_no_redraw (FRAME_WIDGET (f));
4596 }
4597
4598 static void
4599 frame_highlight (struct frame *f)
4600 {
4601 block_input ();
4602 GtkWidget *w = FRAME_WIDGET (f);
4603
4604 char *css = g_strdup_printf ("decoration { border: solid %dpx #%06x; }",
4605 f->border_width,
4606 ((unsigned int) FRAME_X_OUTPUT (f)->border_pixel
4607 & 0x00ffffff));
4608
4609 GtkStyleContext *ctxt = gtk_widget_get_style_context (w);
4610 GtkCssProvider *css_provider = gtk_css_provider_new ();
4611 gtk_css_provider_load_from_data (css_provider, css, -1, NULL);
4612 gtk_style_context_add_provider (ctxt, GTK_STYLE_PROVIDER (css_provider),
4613 GTK_STYLE_PROVIDER_PRIORITY_USER);
4614 g_free (css);
4615
4616 GtkCssProvider *old = FRAME_X_OUTPUT (f)->border_color_css_provider;
4617 FRAME_X_OUTPUT (f)->border_color_css_provider = css_provider;
4618 if (old != NULL)
4619 {
4620 gtk_style_context_remove_provider (ctxt, GTK_STYLE_PROVIDER (old));
4621 g_object_unref (old);
4622 }
4623
4624 unblock_input ();
4625 gui_update_cursor (f, true);
4626 pgtk_set_frame_alpha (f);
4627 }
4628
4629 static void
4630 frame_unhighlight (struct frame *f)
4631 {
4632 GtkWidget *w;
4633 char *css;
4634 GtkStyleContext *ctxt;
4635 GtkCssProvider *css_provider, *old;
4636
4637 block_input ();
4638
4639 w = FRAME_WIDGET (f);
4640
4641 css = g_strdup_printf ("decoration { border: dotted %dpx #ffffff; }",
4642 f->border_width);
4643
4644 ctxt = gtk_widget_get_style_context (w);
4645 css_provider = gtk_css_provider_new ();
4646 gtk_css_provider_load_from_data (css_provider, css, -1, NULL);
4647 gtk_style_context_add_provider (ctxt, GTK_STYLE_PROVIDER (css_provider),
4648 GTK_STYLE_PROVIDER_PRIORITY_USER);
4649 g_free (css);
4650
4651 old = FRAME_X_OUTPUT (f)->border_color_css_provider;
4652 FRAME_X_OUTPUT (f)->border_color_css_provider = css_provider;
4653 if (old != NULL)
4654 {
4655 gtk_style_context_remove_provider (ctxt, GTK_STYLE_PROVIDER (old));
4656 g_object_unref (old);
4657 }
4658
4659 unblock_input ();
4660 gui_update_cursor (f, true);
4661 pgtk_set_frame_alpha (f);
4662 }
4663
4664
4665 void
4666 pgtk_frame_rehighlight (struct pgtk_display_info *dpyinfo)
4667 {
4668 struct frame *old_highlight = dpyinfo->highlight_frame;
4669
4670 if (dpyinfo->x_focus_frame)
4671 {
4672 dpyinfo->highlight_frame
4673 = ((FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame)))
4674 ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
4675 : dpyinfo->x_focus_frame);
4676 if (!FRAME_LIVE_P (dpyinfo->highlight_frame))
4677 {
4678 fset_focus_frame (dpyinfo->x_focus_frame, Qnil);
4679 dpyinfo->highlight_frame = dpyinfo->x_focus_frame;
4680 }
4681 }
4682 else
4683 dpyinfo->highlight_frame = 0;
4684
4685 if (old_highlight)
4686 frame_unhighlight (old_highlight);
4687 if (dpyinfo->highlight_frame)
4688 frame_highlight (dpyinfo->highlight_frame);
4689 }
4690
4691
4692
4693
4694
4695
4696
4697
4698
4699 static void
4700 pgtk_frame_rehighlight_hook (struct frame *frame)
4701 {
4702 pgtk_frame_rehighlight (FRAME_DISPLAY_INFO (frame));
4703 }
4704
4705
4706
4707 static void
4708 pgtk_toggle_invisible_pointer (struct frame *f, bool invisible)
4709 {
4710 Emacs_Cursor cursor;
4711 if (invisible)
4712 cursor = FRAME_DISPLAY_INFO (f)->invisible_cursor;
4713 else
4714 cursor = f->output_data.pgtk->current_cursor;
4715 gdk_window_set_cursor (gtk_widget_get_window (FRAME_GTK_WIDGET (f)),
4716 cursor);
4717 f->pointer_invisible = invisible;
4718
4719
4720
4721 gdk_display_flush (FRAME_X_DISPLAY (f));
4722 }
4723
4724
4725
4726
4727
4728
4729
4730 static void
4731 pgtk_new_focus_frame (struct pgtk_display_info *dpyinfo, struct frame *frame)
4732 {
4733 struct frame *old_focus = dpyinfo->x_focus_frame;
4734
4735
4736 if (frame != dpyinfo->x_focus_frame)
4737 {
4738
4739
4740 dpyinfo->x_focus_frame = frame;
4741
4742 if (old_focus && old_focus->auto_lower)
4743 if (FRAME_GTK_OUTER_WIDGET (old_focus))
4744 gdk_window_lower (gtk_widget_get_window
4745 (FRAME_GTK_OUTER_WIDGET (old_focus)));
4746
4747 if (dpyinfo->x_focus_frame && dpyinfo->x_focus_frame->auto_raise)
4748 if (FRAME_GTK_OUTER_WIDGET (dpyinfo->x_focus_frame))
4749 gdk_window_raise (gtk_widget_get_window
4750 (FRAME_GTK_OUTER_WIDGET (dpyinfo->x_focus_frame)));
4751 }
4752
4753 pgtk_frame_rehighlight (dpyinfo);
4754 }
4755
4756 static void
4757 pgtk_buffer_flipping_unblocked_hook (struct frame *f)
4758 {
4759 block_input ();
4760 flip_cr_context (f);
4761 gtk_widget_queue_draw (FRAME_GTK_WIDGET (f));
4762 unblock_input ();
4763 }
4764
4765 static struct terminal *
4766 pgtk_create_terminal (struct pgtk_display_info *dpyinfo)
4767 {
4768 struct terminal *terminal;
4769
4770 terminal = create_terminal (output_pgtk, &pgtk_redisplay_interface);
4771
4772 terminal->display_info.pgtk = dpyinfo;
4773 dpyinfo->terminal = terminal;
4774
4775 terminal->clear_frame_hook = pgtk_clear_frame;
4776 terminal->ring_bell_hook = pgtk_ring_bell;
4777 terminal->toggle_invisible_pointer_hook = pgtk_toggle_invisible_pointer;
4778 terminal->update_begin_hook = pgtk_update_begin;
4779 terminal->update_end_hook = pgtk_update_end;
4780 terminal->read_socket_hook = pgtk_read_socket;
4781 terminal->frame_up_to_date_hook = pgtk_frame_up_to_date;
4782 terminal->mouse_position_hook = pgtk_mouse_position;
4783 terminal->frame_rehighlight_hook = pgtk_frame_rehighlight_hook;
4784 terminal->buffer_flipping_unblocked_hook = pgtk_buffer_flipping_unblocked_hook;
4785 terminal->frame_raise_lower_hook = pgtk_frame_raise_lower;
4786 terminal->frame_visible_invisible_hook = pgtk_make_frame_visible_invisible;
4787 terminal->fullscreen_hook = pgtk_fullscreen_hook;
4788 terminal->menu_show_hook = pgtk_menu_show;
4789 terminal->activate_menubar_hook = pgtk_activate_menubar;
4790 terminal->popup_dialog_hook = pgtk_popup_dialog;
4791 terminal->change_tab_bar_height_hook = pgtk_change_tab_bar_height;
4792 terminal->set_vertical_scroll_bar_hook = pgtk_set_vertical_scroll_bar;
4793 terminal->set_horizontal_scroll_bar_hook = pgtk_set_horizontal_scroll_bar;
4794 terminal->condemn_scroll_bars_hook = pgtk_condemn_scroll_bars;
4795 terminal->redeem_scroll_bar_hook = pgtk_redeem_scroll_bar;
4796 terminal->judge_scroll_bars_hook = pgtk_judge_scroll_bars;
4797 terminal->get_string_resource_hook = pgtk_get_string_resource;
4798 terminal->delete_frame_hook = pgtk_destroy_window;
4799 terminal->delete_terminal_hook = pgtk_delete_terminal;
4800 terminal->query_frame_background_color = pgtk_query_frame_background_color;
4801 terminal->defined_color_hook = pgtk_defined_color;
4802 terminal->set_new_font_hook = pgtk_new_font;
4803 terminal->set_bitmap_icon_hook = pgtk_bitmap_icon;
4804 terminal->implicit_set_name_hook = pgtk_implicitly_set_name;
4805 terminal->iconify_frame_hook = pgtk_iconify_frame;
4806 terminal->set_scroll_bar_default_width_hook
4807 = pgtk_set_scroll_bar_default_width;
4808 terminal->set_scroll_bar_default_height_hook
4809 = pgtk_set_scroll_bar_default_height;
4810 terminal->set_window_size_hook = pgtk_set_window_size;
4811 terminal->query_colors = pgtk_query_colors;
4812 terminal->get_focus_frame = pgtk_get_focus_frame;
4813 terminal->focus_frame_hook = pgtk_focus_frame;
4814 terminal->set_frame_offset_hook = pgtk_set_offset;
4815 terminal->free_pixmap = pgtk_free_pixmap;
4816 terminal->toolkit_position_hook = pgtk_toolkit_position;
4817
4818
4819
4820 return terminal;
4821 }
4822
4823 struct pgtk_window_is_of_frame_recursive_t
4824 {
4825 GdkWindow *window;
4826 bool result;
4827 GtkWidget *emacs_gtk_fixed;
4828 };
4829
4830 static void
4831 pgtk_window_is_of_frame_recursive (GtkWidget *widget, gpointer data)
4832 {
4833 struct pgtk_window_is_of_frame_recursive_t *datap = data;
4834
4835 if (datap->result)
4836 return;
4837
4838 if (EMACS_IS_FIXED (widget) && widget != datap->emacs_gtk_fixed)
4839 return;
4840
4841 if (gtk_widget_get_window (widget) == datap->window)
4842 {
4843 datap->result = true;
4844 return;
4845 }
4846
4847 if (GTK_IS_CONTAINER (widget))
4848 gtk_container_foreach (GTK_CONTAINER (widget),
4849 pgtk_window_is_of_frame_recursive, datap);
4850 }
4851
4852 static bool
4853 pgtk_window_is_of_frame (struct frame *f, GdkWindow *window)
4854 {
4855 struct pgtk_window_is_of_frame_recursive_t data;
4856 data.window = window;
4857 data.result = false;
4858 data.emacs_gtk_fixed = FRAME_GTK_WIDGET (f);
4859 pgtk_window_is_of_frame_recursive (FRAME_WIDGET (f), &data);
4860 return data.result;
4861 }
4862
4863
4864
4865 static struct frame *
4866 pgtk_any_window_to_frame (GdkWindow *window)
4867 {
4868 Lisp_Object tail, frame;
4869 struct frame *f, *found = NULL;
4870
4871 if (window == NULL)
4872 return NULL;
4873
4874 FOR_EACH_FRAME (tail, frame)
4875 {
4876 if (found)
4877 break;
4878 f = XFRAME (frame);
4879 if (FRAME_PGTK_P (f))
4880 {
4881 if (pgtk_window_is_of_frame (f, window))
4882 found = f;
4883 }
4884 }
4885
4886 return found;
4887 }
4888
4889 static gboolean
4890 pgtk_handle_event (GtkWidget *widget, GdkEvent *event, gpointer *data)
4891 {
4892 struct frame *f;
4893 union buffered_input_event inev;
4894 GtkWidget *frame_widget;
4895 gint x, y;
4896
4897 if (event->type == GDK_TOUCHPAD_PINCH
4898 && (event->touchpad_pinch.phase
4899 != GDK_TOUCHPAD_GESTURE_PHASE_END))
4900 {
4901 f = pgtk_any_window_to_frame (gtk_widget_get_window (widget));
4902 frame_widget = FRAME_GTK_WIDGET (f);
4903
4904 gtk_widget_translate_coordinates (widget, frame_widget,
4905 lrint (event->touchpad_pinch.x),
4906 lrint (event->touchpad_pinch.y),
4907 &x, &y);
4908 if (f)
4909 {
4910
4911 inev.ie.kind = PINCH_EVENT;
4912 XSETFRAME (inev.ie.frame_or_window, f);
4913 XSETINT (inev.ie.x, x);
4914 XSETINT (inev.ie.y, y);
4915 inev.ie.arg = list4 (make_float (event->touchpad_pinch.dx),
4916 make_float (event->touchpad_pinch.dy),
4917 make_float (event->touchpad_pinch.scale),
4918 make_float (event->touchpad_pinch.angle_delta));
4919 inev.ie.modifiers = pgtk_gtk_to_emacs_modifiers (FRAME_DISPLAY_INFO (f),
4920 event->touchpad_pinch.state);
4921 inev.ie.device
4922 = pgtk_get_device_for_event (FRAME_DISPLAY_INFO (f), event);
4923 evq_enqueue (&inev);
4924 }
4925
4926 return TRUE;
4927 }
4928 return FALSE;
4929 }
4930
4931 static void
4932 pgtk_fill_rectangle (struct frame *f, unsigned long color, int x, int y,
4933 int width, int height, bool respect_alpha_background)
4934 {
4935 cairo_t *cr;
4936 cr = pgtk_begin_cr_clip (f);
4937 pgtk_set_cr_source_with_color (f, color, respect_alpha_background);
4938 cairo_rectangle (cr, x, y, width, height);
4939 cairo_fill (cr);
4940 pgtk_end_cr_clip (f);
4941 }
4942
4943 void
4944 pgtk_clear_under_internal_border (struct frame *f)
4945 {
4946 if (FRAME_INTERNAL_BORDER_WIDTH (f) > 0
4947 && (!FRAME_GTK_OUTER_WIDGET (f)
4948 || gtk_widget_get_realized (FRAME_GTK_OUTER_WIDGET (f))))
4949 {
4950 int border = FRAME_INTERNAL_BORDER_WIDTH (f);
4951 int width = FRAME_PIXEL_WIDTH (f);
4952 int height = FRAME_PIXEL_HEIGHT (f);
4953 int margin = FRAME_TOP_MARGIN_HEIGHT (f);
4954 int bottom_margin = FRAME_BOTTOM_MARGIN_HEIGHT (f);
4955 int face_id = (FRAME_PARENT_FRAME (f)
4956 ? (!NILP (Vface_remapping_alist)
4957 ? lookup_basic_face (NULL, f,
4958 CHILD_FRAME_BORDER_FACE_ID)
4959 : CHILD_FRAME_BORDER_FACE_ID)
4960 : (!NILP (Vface_remapping_alist)
4961 ? lookup_basic_face (NULL, f,
4962 INTERNAL_BORDER_FACE_ID)
4963 : INTERNAL_BORDER_FACE_ID));
4964 struct face *face = FACE_FROM_ID_OR_NULL (f, face_id);
4965
4966 block_input ();
4967
4968 if (face)
4969 {
4970 fill_background_by_face (f, face, 0, margin, width, border);
4971 fill_background_by_face (f, face, 0, 0, border, height);
4972 fill_background_by_face (f, face, width - border, 0, border,
4973 height);
4974 fill_background_by_face (f, face, 0, (height
4975 - bottom_margin
4976 - border),
4977 width, border);
4978 }
4979 else
4980 {
4981 pgtk_clear_area (f, 0, 0, border, height);
4982 pgtk_clear_area (f, 0, margin, width, border);
4983 pgtk_clear_area (f, width - border, 0, border, height);
4984 pgtk_clear_area (f, 0, height - bottom_margin - border,
4985 width, border);
4986 }
4987
4988 unblock_input ();
4989 }
4990 }
4991
4992 static gboolean
4993 pgtk_handle_draw (GtkWidget *widget, cairo_t *cr, gpointer *data)
4994 {
4995 struct frame *f;
4996
4997 GdkWindow *win = gtk_widget_get_window (widget);
4998
4999 if (win != NULL)
5000 {
5001 cairo_surface_t *src = NULL;
5002 f = pgtk_any_window_to_frame (win);
5003 if (f != NULL)
5004 {
5005 src = FRAME_X_OUTPUT (f)->cr_surface_visible_bell;
5006 if (src == NULL && FRAME_CR_ACTIVE_CONTEXT (f) != NULL)
5007 src = cairo_get_target (FRAME_CR_ACTIVE_CONTEXT (f));
5008 }
5009 if (src != NULL)
5010 {
5011 cairo_set_source_surface (cr, src, 0, 0);
5012 cairo_paint (cr);
5013 }
5014 }
5015 return FALSE;
5016 }
5017
5018 static void
5019 size_allocate (GtkWidget *widget, GtkAllocation *alloc,
5020 gpointer user_data)
5021 {
5022 struct frame *f = pgtk_any_window_to_frame (gtk_widget_get_window (widget));
5023
5024 if (!f)
5025 f = user_data;
5026
5027 if (f)
5028 {
5029 xg_frame_resized (f, alloc->width, alloc->height);
5030 pgtk_cr_update_surface_desired_size (f, alloc->width, alloc->height, false);
5031 }
5032 }
5033
5034 static void
5035 get_modifier_values (int *mod_ctrl, int *mod_meta, int *mod_alt,
5036 int *mod_hyper, int *mod_super)
5037 {
5038 Lisp_Object tem;
5039
5040 *mod_ctrl = ctrl_modifier;
5041 *mod_meta = meta_modifier;
5042 *mod_alt = alt_modifier;
5043 *mod_hyper = hyper_modifier;
5044 *mod_super = super_modifier;
5045
5046 tem = Fget (Vx_ctrl_keysym, Qmodifier_value);
5047 if (INTEGERP (tem))
5048 *mod_ctrl = XFIXNUM (tem) & INT_MAX;
5049 tem = Fget (Vx_alt_keysym, Qmodifier_value);
5050 if (INTEGERP (tem))
5051 *mod_alt = XFIXNUM (tem) & INT_MAX;
5052 tem = Fget (Vx_meta_keysym, Qmodifier_value);
5053 if (INTEGERP (tem))
5054 *mod_meta = XFIXNUM (tem) & INT_MAX;
5055 tem = Fget (Vx_hyper_keysym, Qmodifier_value);
5056 if (INTEGERP (tem))
5057 *mod_hyper = XFIXNUM (tem) & INT_MAX;
5058 tem = Fget (Vx_super_keysym, Qmodifier_value);
5059 if (INTEGERP (tem))
5060 *mod_super = XFIXNUM (tem) & INT_MAX;
5061 }
5062
5063 int
5064 pgtk_gtk_to_emacs_modifiers (struct pgtk_display_info *dpyinfo, int state)
5065 {
5066 int mod_ctrl;
5067 int mod_meta;
5068 int mod_alt;
5069 int mod_hyper;
5070 int mod_super;
5071 int mod;
5072
5073 get_modifier_values (&mod_ctrl, &mod_meta, &mod_alt, &mod_hyper,
5074 &mod_super);
5075
5076 mod = 0;
5077 if (state & GDK_SHIFT_MASK)
5078 mod |= shift_modifier;
5079 if (state & GDK_CONTROL_MASK)
5080 mod |= mod_ctrl;
5081 if (state & GDK_META_MASK || state & GDK_MOD1_MASK)
5082 mod |= mod_meta;
5083 if (state & GDK_SUPER_MASK)
5084 mod |= mod_super;
5085 if (state & GDK_HYPER_MASK)
5086 mod |= mod_hyper;
5087
5088 return mod;
5089 }
5090
5091 int
5092 pgtk_emacs_to_gtk_modifiers (struct pgtk_display_info *dpyinfo, int state)
5093 {
5094 int mod_ctrl;
5095 int mod_meta;
5096 int mod_alt;
5097 int mod_hyper;
5098 int mod_super;
5099 int mask;
5100
5101 get_modifier_values (&mod_ctrl, &mod_meta, &mod_alt, &mod_hyper,
5102 &mod_super);
5103
5104 mask = 0;
5105 if (state & mod_super)
5106 mask |= GDK_SUPER_MASK;
5107 if (state & mod_hyper)
5108 mask |= GDK_HYPER_MASK;
5109 if (state & shift_modifier)
5110 mask |= GDK_SHIFT_MASK;
5111 if (state & mod_ctrl)
5112 mask |= GDK_CONTROL_MASK;
5113 if (state & mod_meta)
5114 mask |= GDK_MOD1_MASK;
5115 return mask;
5116 }
5117
5118 #define IsCursorKey(keysym) (0xff50 <= (keysym) && (keysym) < 0xff60)
5119 #define IsMiscFunctionKey(keysym) (0xff60 <= (keysym) && (keysym) < 0xff6c)
5120 #define IsKeypadKey(keysym) (0xff80 <= (keysym) && (keysym) < 0xffbe)
5121 #define IsFunctionKey(keysym) (0xffbe <= (keysym) && (keysym) < 0xffe1)
5122 #define IsModifierKey(keysym) \
5123 ((((keysym) >= GDK_KEY_Shift_L) && ((keysym) <= GDK_KEY_Hyper_R)) \
5124 || (((keysym) >= GDK_KEY_ISO_Lock) && ((keysym) <= GDK_KEY_ISO_Level5_Lock)) \
5125 || ((keysym) == GDK_KEY_Mode_switch) \
5126 || ((keysym) == GDK_KEY_Num_Lock))
5127
5128
5129 void
5130 pgtk_enqueue_string (struct frame *f, gchar *str)
5131 {
5132 gunichar *ustr, *uptr;
5133
5134 uptr = ustr = g_utf8_to_ucs4 (str, -1, NULL, NULL, NULL);
5135 if (ustr == NULL)
5136 return;
5137 for (; *ustr != 0; ustr++)
5138 {
5139 union buffered_input_event inev;
5140 Lisp_Object c = make_fixnum (*ustr);
5141 EVENT_INIT (inev.ie);
5142 inev.ie.kind = (SINGLE_BYTE_CHAR_P (XFIXNAT (c))
5143 ? ASCII_KEYSTROKE_EVENT
5144 : MULTIBYTE_CHAR_KEYSTROKE_EVENT);
5145 inev.ie.arg = Qnil;
5146 inev.ie.code = XFIXNAT (c);
5147 XSETFRAME (inev.ie.frame_or_window, f);
5148 inev.ie.modifiers = 0;
5149 inev.ie.timestamp = 0;
5150 evq_enqueue (&inev);
5151 }
5152
5153 g_free (uptr);
5154 }
5155
5156 void
5157 pgtk_enqueue_preedit (struct frame *f, Lisp_Object preedit)
5158 {
5159 union buffered_input_event inev;
5160 EVENT_INIT (inev.ie);
5161 inev.ie.kind = PREEDIT_TEXT_EVENT;
5162 inev.ie.arg = preedit;
5163 inev.ie.code = 0;
5164 XSETFRAME (inev.ie.frame_or_window, f);
5165 inev.ie.modifiers = 0;
5166 inev.ie.timestamp = 0;
5167 evq_enqueue (&inev);
5168 }
5169
5170 static gboolean
5171 key_press_event (GtkWidget *widget, GdkEvent *event, gpointer *user_data)
5172 {
5173 union buffered_input_event inev;
5174 ptrdiff_t nbytes;
5175 Mouse_HLInfo *hlinfo;
5176 struct frame *f;
5177 struct pgtk_display_info *dpyinfo;
5178
5179 f = pgtk_any_window_to_frame (gtk_widget_get_window (widget));
5180 EVENT_INIT (inev.ie);
5181 hlinfo = MOUSE_HL_INFO (f);
5182 nbytes = 0;
5183
5184
5185
5186 if (!hlinfo->mouse_face_hidden && INTEGERP (Vmouse_highlight))
5187 {
5188 clear_mouse_face (hlinfo);
5189 hlinfo->mouse_face_hidden = true;
5190 }
5191
5192 if (f != 0)
5193 {
5194 guint keysym, orig_keysym;
5195
5196
5197
5198
5199
5200
5201
5202
5203
5204
5205
5206 unsigned char copy_buffer[513];
5207 unsigned char *copy_bufptr = copy_buffer;
5208 int copy_bufsiz = sizeof (copy_buffer);
5209 int modifiers;
5210 Lisp_Object c;
5211 guint state;
5212
5213 dpyinfo = FRAME_DISPLAY_INFO (f);
5214
5215
5216
5217 dpyinfo->last_user_time = event->key.time;
5218
5219 state = event->key.state;
5220
5221
5222
5223
5224 if (!(event->key.state & (GDK_SUPER_MASK | GDK_HYPER_MASK)))
5225 {
5226 if (pgtk_im_filter_keypress (f, &event->key))
5227 return TRUE;
5228 }
5229
5230 state |= pgtk_emacs_to_gtk_modifiers (FRAME_DISPLAY_INFO (f),
5231 extra_keyboard_modifiers);
5232 modifiers = state;
5233
5234
5235
5236
5237
5238 state &= ~GDK_CONTROL_MASK;
5239 state &= ~(GDK_META_MASK
5240 | GDK_SUPER_MASK | GDK_HYPER_MASK | GDK_MOD1_MASK);
5241
5242 nbytes = event->key.length;
5243 if (nbytes > copy_bufsiz)
5244 nbytes = copy_bufsiz;
5245 memcpy (copy_bufptr, event->key.string, nbytes);
5246
5247 keysym = event->key.keyval;
5248 orig_keysym = keysym;
5249
5250
5251 XSETFRAME (inev.ie.frame_or_window, f);
5252 inev.ie.modifiers
5253 = pgtk_gtk_to_emacs_modifiers (FRAME_DISPLAY_INFO (f), modifiers);
5254 inev.ie.timestamp = event->key.time;
5255
5256
5257
5258 if (keysym >= 32 && keysym < 128)
5259
5260 {
5261 inev.ie.kind = ASCII_KEYSTROKE_EVENT;
5262 inev.ie.code = keysym;
5263
5264 inev.ie.device
5265 = pgtk_get_device_for_event (FRAME_DISPLAY_INFO (f), event);
5266 goto done;
5267 }
5268
5269
5270 if (keysym >= 0x01000000 && keysym <= 0x0110FFFF)
5271 {
5272 if (keysym < 0x01000080)
5273 inev.ie.kind = ASCII_KEYSTROKE_EVENT;
5274 else
5275 inev.ie.kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT;
5276 inev.ie.code = keysym & 0xFFFFFF;
5277
5278 inev.ie.device
5279 = pgtk_get_device_for_event (FRAME_DISPLAY_INFO (f), event);
5280 goto done;
5281 }
5282
5283
5284 if (HASH_TABLE_P (Vpgtk_keysym_table)
5285 && (c = Fgethash (make_fixnum (keysym),
5286 Vpgtk_keysym_table, Qnil), FIXNATP (c)))
5287 {
5288 inev.ie.kind = (SINGLE_BYTE_CHAR_P (XFIXNAT (c))
5289 ? ASCII_KEYSTROKE_EVENT
5290 : MULTIBYTE_CHAR_KEYSTROKE_EVENT);
5291 inev.ie.code = XFIXNAT (c);
5292
5293 inev.ie.device
5294 = pgtk_get_device_for_event (FRAME_DISPLAY_INFO (f), event);
5295 goto done;
5296 }
5297
5298
5299 if (((keysym >= GDK_KEY_BackSpace && keysym <= GDK_KEY_Escape)
5300 || keysym == GDK_KEY_Delete
5301 #ifdef GDK_KEY_ISO_Left_Tab
5302 || (keysym >= GDK_KEY_ISO_Left_Tab && keysym <= GDK_KEY_ISO_Enter)
5303 #endif
5304 || IsCursorKey (keysym)
5305 || IsMiscFunctionKey (keysym)
5306 #ifdef HPUX
5307
5308
5309
5310
5311 || (GDK_KEY_Select <= keysym && keysym < GDK_KEY_KP_Space)
5312 #endif
5313 #ifdef GDK_KEY_dead_circumflex
5314 || orig_keysym == GDK_KEY_dead_circumflex
5315 #endif
5316 #ifdef GDK_KEY_dead_grave
5317 || orig_keysym == GDK_KEY_dead_grave
5318 #endif
5319 #ifdef GDK_KEY_dead_tilde
5320 || orig_keysym == GDK_KEY_dead_tilde
5321 #endif
5322 #ifdef GDK_KEY_dead_diaeresis
5323 || orig_keysym == GDK_KEY_dead_diaeresis
5324 #endif
5325 #ifdef GDK_KEY_dead_macron
5326 || orig_keysym == GDK_KEY_dead_macron
5327 #endif
5328 #ifdef GDK_KEY_dead_degree
5329 || orig_keysym == GDK_KEY_dead_degree
5330 #endif
5331 #ifdef GDK_KEY_dead_acute
5332 || orig_keysym == GDK_KEY_dead_acute
5333 #endif
5334 #ifdef GDK_KEY_dead_cedilla
5335 || orig_keysym == GDK_KEY_dead_cedilla
5336 #endif
5337 #ifdef GDK_KEY_dead_breve
5338 || orig_keysym == GDK_KEY_dead_breve
5339 #endif
5340 #ifdef GDK_KEY_dead_ogonek
5341 || orig_keysym == GDK_KEY_dead_ogonek
5342 #endif
5343 #ifdef GDK_KEY_dead_caron
5344 || orig_keysym == GDK_KEY_dead_caron
5345 #endif
5346 #ifdef GDK_KEY_dead_doubleacute
5347 || orig_keysym == GDK_KEY_dead_doubleacute
5348 #endif
5349 #ifdef GDK_KEY_dead_abovedot
5350 || orig_keysym == GDK_KEY_dead_abovedot
5351 #endif
5352 || IsKeypadKey (keysym)
5353 || IsFunctionKey (keysym)
5354
5355 || (orig_keysym & (1 << 28))
5356 || (keysym != GDK_KEY_VoidSymbol && nbytes == 0))
5357 && !(event->key.is_modifier
5358 || IsModifierKey (orig_keysym)
5359
5360
5361
5362
5363
5364 #if defined GDK_KEY_ISO_Lock && defined GDK_KEY_ISO_Last_Group_Lock
5365 || (GDK_KEY_ISO_Lock <= orig_keysym
5366 && orig_keysym <= GDK_KEY_ISO_Last_Group_Lock)
5367 #endif
5368 ))
5369 {
5370
5371
5372 inev.ie.kind = NON_ASCII_KEYSTROKE_EVENT;
5373 inev.ie.code = keysym;
5374
5375 inev.ie.device
5376 = pgtk_get_device_for_event (FRAME_DISPLAY_INFO (f), event);
5377 goto done;
5378 }
5379
5380 {
5381 inev.ie.kind = MULTIBYTE_CHAR_KEYSTROKE_EVENT;
5382 inev.ie.arg = make_unibyte_string ((char *) copy_bufptr, nbytes);
5383 inev.ie.device
5384 = pgtk_get_device_for_event (FRAME_DISPLAY_INFO (f), event);
5385
5386 if (keysym == GDK_KEY_VoidSymbol)
5387 goto done;
5388 }
5389 }
5390
5391 done:
5392 if (inev.ie.kind != NO_EVENT)
5393 {
5394 XSETFRAME (inev.ie.frame_or_window, f);
5395 evq_enqueue (&inev);
5396 }
5397
5398 return TRUE;
5399 }
5400
5401 static struct pgtk_display_info *
5402 pgtk_display_info_for_display (GdkDisplay *dpy)
5403 {
5404 struct pgtk_display_info *dpyinfo;
5405
5406 for (dpyinfo = x_display_list; dpyinfo; dpyinfo = dpyinfo->next)
5407 {
5408 if (dpyinfo->display == dpy)
5409 return dpyinfo;
5410 }
5411
5412 return NULL;
5413 }
5414
5415 static gboolean
5416 key_release_event (GtkWidget *widget,
5417 GdkEvent *event,
5418 gpointer *user_data)
5419 {
5420 GdkDisplay *display;
5421 struct pgtk_display_info *dpyinfo;
5422
5423 display = gtk_widget_get_display (widget);
5424 dpyinfo = pgtk_display_info_for_display (display);
5425
5426 if (dpyinfo)
5427
5428
5429
5430 dpyinfo->last_user_time = event->key.time;
5431
5432 return TRUE;
5433 }
5434
5435 static gboolean
5436 configure_event (GtkWidget *widget,
5437 GdkEvent *event,
5438 gpointer *user_data)
5439 {
5440 struct frame *f = pgtk_any_window_to_frame (event->configure.window);
5441
5442 if (f && widget == FRAME_GTK_OUTER_WIDGET (f))
5443 {
5444 if (any_help_event_p)
5445 {
5446 Lisp_Object frame;
5447 if (f)
5448 XSETFRAME (frame, f);
5449 else
5450 frame = Qnil;
5451 help_echo_string = Qnil;
5452 gen_help_event (Qnil, frame, Qnil, Qnil, 0);
5453 }
5454
5455 if (f->win_gravity == NorthWestGravity)
5456 gtk_window_get_position (GTK_WINDOW (widget),
5457 &f->left_pos, &f->top_pos);
5458 else
5459 {
5460 f->top_pos = event->configure.y;
5461 f->left_pos = event->configure.x;
5462 }
5463 }
5464 return FALSE;
5465 }
5466
5467 static gboolean
5468 map_event (GtkWidget *widget,
5469 GdkEvent *event,
5470 gpointer *user_data)
5471 {
5472 struct frame *f = pgtk_any_window_to_frame (event->any.window);
5473 union buffered_input_event inev;
5474
5475 EVENT_INIT (inev.ie);
5476 inev.ie.kind = NO_EVENT;
5477 inev.ie.arg = Qnil;
5478
5479 if (f)
5480 {
5481 bool iconified = FRAME_ICONIFIED_P (f);
5482
5483
5484
5485 if (!FRAME_X_OUTPUT (f)->has_been_visible)
5486 set_fullscreen_state (f);
5487
5488 if (!iconified)
5489 {
5490
5491
5492 if (FRAME_Z_GROUP (f) == z_group_above)
5493 pgtk_set_z_group (f, Qabove, Qnil);
5494 else if (FRAME_Z_GROUP (f) == z_group_below)
5495 pgtk_set_z_group (f, Qbelow, Qnil);
5496 }
5497
5498 SET_FRAME_VISIBLE (f, 1);
5499 SET_FRAME_ICONIFIED (f, false);
5500 FRAME_X_OUTPUT (f)->has_been_visible = true;
5501
5502 if (iconified)
5503 {
5504 inev.ie.kind = DEICONIFY_EVENT;
5505 XSETFRAME (inev.ie.frame_or_window, f);
5506 }
5507 }
5508
5509 if (inev.ie.kind != NO_EVENT)
5510 evq_enqueue (&inev);
5511 return FALSE;
5512 }
5513
5514 static gboolean
5515 window_state_event (GtkWidget *widget,
5516 GdkEvent *event,
5517 gpointer *user_data)
5518 {
5519 struct frame *f = pgtk_any_window_to_frame (event->window_state.window);
5520 GdkWindowState new_state;
5521 union buffered_input_event inev;
5522
5523 new_state = event->window_state.new_window_state;
5524
5525 EVENT_INIT (inev.ie);
5526 inev.ie.kind = NO_EVENT;
5527 inev.ie.arg = Qnil;
5528
5529 if (new_state & GDK_WINDOW_STATE_FULLSCREEN)
5530 store_frame_param (f, Qfullscreen, Qfullboth);
5531 else if (new_state & GDK_WINDOW_STATE_MAXIMIZED)
5532 store_frame_param (f, Qfullscreen, Qmaximized);
5533 else if ((new_state & GDK_WINDOW_STATE_TOP_TILED)
5534 && (new_state & GDK_WINDOW_STATE_BOTTOM_TILED)
5535 && !(new_state & GDK_WINDOW_STATE_TOP_RESIZABLE)
5536 && !(new_state & GDK_WINDOW_STATE_BOTTOM_RESIZABLE))
5537 store_frame_param (f, Qfullscreen, Qfullheight);
5538 else if ((new_state & GDK_WINDOW_STATE_LEFT_TILED)
5539 && (new_state & GDK_WINDOW_STATE_RIGHT_TILED)
5540 && !(new_state & GDK_WINDOW_STATE_LEFT_RESIZABLE)
5541 && !(new_state & GDK_WINDOW_STATE_RIGHT_RESIZABLE))
5542 store_frame_param (f, Qfullscreen, Qfullwidth);
5543 else
5544 store_frame_param (f, Qfullscreen, Qnil);
5545
5546
5547
5548
5549
5550
5551
5552
5553
5554
5555
5556
5557
5558
5559
5560
5561
5562
5563
5564
5565 if (new_state & GDK_WINDOW_STATE_ICONIFIED)
5566 {
5567 SET_FRAME_ICONIFIED (f, true);
5568 SET_FRAME_VISIBLE (f, false);
5569 }
5570 else
5571 {
5572 FRAME_X_OUTPUT (f)->has_been_visible = true;
5573 inev.ie.kind = DEICONIFY_EVENT;
5574 XSETFRAME (inev.ie.frame_or_window, f);
5575 SET_FRAME_ICONIFIED (f, false);
5576 SET_FRAME_VISIBLE (f, true);
5577 }
5578
5579 if (new_state & GDK_WINDOW_STATE_STICKY)
5580 store_frame_param (f, Qsticky, Qt);
5581 else
5582 store_frame_param (f, Qsticky, Qnil);
5583
5584 if (inev.ie.kind != NO_EVENT)
5585 evq_enqueue (&inev);
5586 return FALSE;
5587 }
5588
5589 static gboolean
5590 delete_event (GtkWidget *widget,
5591 GdkEvent *event, gpointer *user_data)
5592 {
5593 struct frame *f = pgtk_any_window_to_frame (event->any.window);
5594 union buffered_input_event inev;
5595
5596 EVENT_INIT (inev.ie);
5597 inev.ie.kind = NO_EVENT;
5598 inev.ie.arg = Qnil;
5599
5600 if (f)
5601 {
5602 inev.ie.kind = DELETE_WINDOW_EVENT;
5603 XSETFRAME (inev.ie.frame_or_window, f);
5604 }
5605
5606 if (inev.ie.kind != NO_EVENT)
5607 evq_enqueue (&inev);
5608 return TRUE;
5609 }
5610
5611
5612
5613
5614
5615
5616
5617
5618
5619
5620 static void
5621 pgtk_focus_changed (gboolean is_enter, int state,
5622 struct pgtk_display_info *dpyinfo, struct frame *frame,
5623 union buffered_input_event *bufp)
5624 {
5625 if (is_enter)
5626 {
5627 if (dpyinfo->x_focus_event_frame != frame)
5628 {
5629 pgtk_new_focus_frame (dpyinfo, frame);
5630 dpyinfo->x_focus_event_frame = frame;
5631
5632
5633
5634
5635 bufp->ie.arg = (((NILP (Vterminal_frame)
5636 || !FRAME_PGTK_P (XFRAME (Vterminal_frame))
5637 || EQ (Fdaemonp (), Qt))
5638 && CONSP (Vframe_list)
5639 && !NILP (XCDR (Vframe_list))) ? Qt : Qnil);
5640 bufp->ie.kind = FOCUS_IN_EVENT;
5641 XSETFRAME (bufp->ie.frame_or_window, frame);
5642 }
5643
5644 frame->output_data.pgtk->focus_state |= state;
5645
5646 }
5647 else
5648 {
5649 frame->output_data.pgtk->focus_state &= ~state;
5650
5651 if (dpyinfo->x_focus_event_frame == frame)
5652 {
5653 dpyinfo->x_focus_event_frame = 0;
5654 pgtk_new_focus_frame (dpyinfo, NULL);
5655
5656 bufp->ie.kind = FOCUS_OUT_EVENT;
5657 XSETFRAME (bufp->ie.frame_or_window, frame);
5658 }
5659
5660 if (frame->pointer_invisible)
5661 pgtk_toggle_invisible_pointer (frame, false);
5662 }
5663 }
5664
5665 static gboolean
5666 enter_notify_event (GtkWidget *widget, GdkEvent *event,
5667 gpointer *user_data)
5668 {
5669 union buffered_input_event inev;
5670 struct frame *frame
5671 = pgtk_any_window_to_frame (gtk_widget_get_window (widget));
5672
5673 if (frame == NULL)
5674 return FALSE;
5675
5676 struct pgtk_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
5677 struct frame *focus_frame = dpyinfo->x_focus_frame;
5678 int focus_state
5679 = focus_frame ? focus_frame->output_data.pgtk->focus_state : 0;
5680
5681 EVENT_INIT (inev.ie);
5682 inev.ie.kind = NO_EVENT;
5683 inev.ie.arg = Qnil;
5684
5685 if (event->crossing.detail != GDK_NOTIFY_INFERIOR
5686 && event->crossing.focus && !(focus_state & FOCUS_EXPLICIT))
5687 pgtk_focus_changed (TRUE, FOCUS_IMPLICIT, dpyinfo, frame, &inev);
5688 if (inev.ie.kind != NO_EVENT)
5689 evq_enqueue (&inev);
5690 return TRUE;
5691 }
5692
5693 static gboolean
5694 leave_notify_event (GtkWidget *widget, GdkEvent *event,
5695 gpointer *user_data)
5696 {
5697 union buffered_input_event inev;
5698 struct frame *frame
5699 = pgtk_any_window_to_frame (gtk_widget_get_window (widget));
5700
5701 if (frame == NULL)
5702 return FALSE;
5703
5704 struct pgtk_display_info *dpyinfo = FRAME_DISPLAY_INFO (frame);
5705 struct frame *focus_frame = dpyinfo->x_focus_frame;
5706 int focus_state
5707 = focus_frame ? focus_frame->output_data.pgtk->focus_state : 0;
5708 Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (frame);
5709
5710 if (frame == hlinfo->mouse_face_mouse_frame)
5711 {
5712
5713
5714 clear_mouse_face (hlinfo);
5715 hlinfo->mouse_face_mouse_frame = 0;
5716 }
5717
5718 EVENT_INIT (inev.ie);
5719 inev.ie.kind = NO_EVENT;
5720 inev.ie.arg = Qnil;
5721
5722 if (event->crossing.detail != GDK_NOTIFY_INFERIOR
5723 && event->crossing.focus && !(focus_state & FOCUS_EXPLICIT))
5724 pgtk_focus_changed (FALSE, FOCUS_IMPLICIT, dpyinfo, frame, &inev);
5725
5726 if (frame)
5727 {
5728 if (any_help_event_p)
5729 {
5730 Lisp_Object frame_obj;
5731 XSETFRAME (frame_obj, frame);
5732 help_echo_string = Qnil;
5733 gen_help_event (Qnil, frame_obj, Qnil, Qnil, 0);
5734 }
5735 }
5736
5737 if (inev.ie.kind != NO_EVENT)
5738 evq_enqueue (&inev);
5739 return TRUE;
5740 }
5741
5742 static gboolean
5743 focus_in_event (GtkWidget *widget, GdkEvent *event, gpointer *user_data)
5744 {
5745 union buffered_input_event inev;
5746 struct frame *frame
5747 = pgtk_any_window_to_frame (gtk_widget_get_window (widget));
5748
5749 if (frame == NULL)
5750 return TRUE;
5751
5752 EVENT_INIT (inev.ie);
5753 inev.ie.kind = NO_EVENT;
5754 inev.ie.arg = Qnil;
5755
5756 pgtk_focus_changed (TRUE, FOCUS_EXPLICIT,
5757 FRAME_DISPLAY_INFO (frame), frame, &inev);
5758 if (inev.ie.kind != NO_EVENT)
5759 evq_enqueue (&inev);
5760
5761 pgtk_im_focus_in (frame);
5762
5763 return TRUE;
5764 }
5765
5766 static gboolean
5767 focus_out_event (GtkWidget *widget, GdkEvent *event, gpointer *user_data)
5768 {
5769 union buffered_input_event inev;
5770 struct frame *frame
5771 = pgtk_any_window_to_frame (gtk_widget_get_window (widget));
5772
5773 if (frame == NULL)
5774 return TRUE;
5775
5776 EVENT_INIT (inev.ie);
5777 inev.ie.kind = NO_EVENT;
5778 inev.ie.arg = Qnil;
5779
5780 pgtk_focus_changed (FALSE, FOCUS_EXPLICIT,
5781 FRAME_DISPLAY_INFO (frame), frame, &inev);
5782 if (inev.ie.kind != NO_EVENT)
5783 evq_enqueue (&inev);
5784
5785 pgtk_im_focus_out (frame);
5786
5787 return TRUE;
5788 }
5789
5790
5791
5792
5793
5794
5795
5796
5797
5798 static bool
5799 note_mouse_movement (struct frame *frame,
5800 const GdkEventMotion *event)
5801 {
5802 XRectangle *r;
5803 struct pgtk_display_info *dpyinfo;
5804
5805 if (!FRAME_X_OUTPUT (frame))
5806 return false;
5807
5808 dpyinfo = FRAME_DISPLAY_INFO (frame);
5809 dpyinfo->last_mouse_movement_time = event->time;
5810 dpyinfo->last_mouse_motion_frame = frame;
5811 dpyinfo->last_mouse_motion_x = event->x;
5812 dpyinfo->last_mouse_motion_y = event->y;
5813
5814 if (event->window != gtk_widget_get_window (FRAME_GTK_WIDGET (frame)))
5815 {
5816 frame->mouse_moved = true;
5817 dpyinfo->last_mouse_scroll_bar = NULL;
5818 note_mouse_highlight (frame, -1, -1);
5819 dpyinfo->last_mouse_glyph_frame = NULL;
5820 frame->last_mouse_device
5821 = pgtk_get_device_for_event (FRAME_DISPLAY_INFO (frame),
5822 (GdkEvent *) event);
5823 return true;
5824 }
5825
5826
5827
5828 r = &dpyinfo->last_mouse_glyph;
5829 if (frame != dpyinfo->last_mouse_glyph_frame
5830 || event->x < r->x || event->x >= r->x + r->width
5831 || event->y < r->y || event->y >= r->y + r->height)
5832 {
5833 frame->mouse_moved = true;
5834 dpyinfo->last_mouse_scroll_bar = NULL;
5835 note_mouse_highlight (frame, event->x, event->y);
5836
5837 remember_mouse_glyph (frame, event->x, event->y, r);
5838 dpyinfo->last_mouse_glyph_frame = frame;
5839 frame->last_mouse_device
5840 = pgtk_get_device_for_event (FRAME_DISPLAY_INFO (frame),
5841 (GdkEvent *) event);
5842 return true;
5843 }
5844
5845 return false;
5846 }
5847
5848 static gboolean
5849 motion_notify_event (GtkWidget *widget, GdkEvent *event,
5850 gpointer *user_data)
5851 {
5852 union buffered_input_event inev;
5853 struct frame *f, *frame;
5854 struct pgtk_display_info *dpyinfo;
5855 Mouse_HLInfo *hlinfo;
5856
5857 EVENT_INIT (inev.ie);
5858 inev.ie.kind = NO_EVENT;
5859 inev.ie.arg = Qnil;
5860
5861 previous_help_echo_string = help_echo_string;
5862 help_echo_string = Qnil;
5863
5864 frame = pgtk_any_window_to_frame (gtk_widget_get_window (widget));
5865 dpyinfo = FRAME_DISPLAY_INFO (frame);
5866 f = (gui_mouse_grabbed (dpyinfo) ? dpyinfo->last_mouse_frame
5867 : pgtk_any_window_to_frame (gtk_widget_get_window (widget)));
5868 hlinfo = MOUSE_HL_INFO (f);
5869
5870 if (hlinfo->mouse_face_hidden)
5871 {
5872 hlinfo->mouse_face_hidden = false;
5873 clear_mouse_face (hlinfo);
5874 }
5875
5876 if (f && xg_event_is_for_scrollbar (f, event, false))
5877 f = 0;
5878
5879 if (f)
5880 {
5881
5882
5883
5884 if (!NILP (Vmouse_autoselect_window)
5885
5886
5887
5888
5889
5890 && !MINI_WINDOW_P (XWINDOW (selected_window))
5891
5892
5893 && (f == XFRAME (selected_frame) || !NILP (focus_follows_mouse)))
5894 {
5895 static Lisp_Object last_mouse_window;
5896 Lisp_Object window = window_from_coordinates
5897 (f, event->motion.x, event->motion.y, 0, false, false);
5898
5899
5900
5901
5902
5903
5904
5905
5906
5907 if (WINDOWP (window)
5908 && !EQ (window, last_mouse_window)
5909 && !EQ (window, selected_window))
5910 {
5911 inev.ie.kind = SELECT_WINDOW_EVENT;
5912 inev.ie.frame_or_window = window;
5913 }
5914
5915
5916 last_mouse_window = window;
5917 }
5918
5919 if (!note_mouse_movement (f, &event->motion))
5920 help_echo_string = previous_help_echo_string;
5921 }
5922 else
5923
5924
5925 clear_mouse_face (hlinfo);
5926
5927
5928
5929 int do_help = 0;
5930 if (!NILP (help_echo_string) || !NILP (previous_help_echo_string))
5931 do_help = 1;
5932
5933 if (inev.ie.kind != NO_EVENT)
5934 evq_enqueue (&inev);
5935
5936 if (do_help > 0)
5937 {
5938 Lisp_Object frame;
5939
5940 if (f)
5941 XSETFRAME (frame, f);
5942 else
5943 frame = Qnil;
5944
5945 any_help_event_p = true;
5946 gen_help_event (help_echo_string, frame, help_echo_window,
5947 help_echo_object, help_echo_pos);
5948 }
5949
5950 return TRUE;
5951 }
5952
5953
5954
5955
5956
5957
5958 static Lisp_Object
5959 construct_mouse_click (struct input_event *result,
5960 const GdkEventButton *event,
5961 struct frame *f)
5962 {
5963
5964
5965 result->kind = MOUSE_CLICK_EVENT;
5966 result->code = event->button - 1;
5967 result->timestamp = event->time;
5968 result->modifiers = (pgtk_gtk_to_emacs_modifiers (FRAME_DISPLAY_INFO (f),
5969 event->state)
5970 | (event->type == GDK_BUTTON_RELEASE
5971 ? up_modifier : down_modifier));
5972
5973 XSETINT (result->x, event->x);
5974 XSETINT (result->y, event->y);
5975 XSETFRAME (result->frame_or_window, f);
5976 result->arg = Qnil;
5977 result->device = pgtk_get_device_for_event (FRAME_DISPLAY_INFO (f),
5978 (GdkEvent *) event);
5979 return Qnil;
5980 }
5981
5982 static gboolean
5983 button_event (GtkWidget *widget, GdkEvent *event,
5984 gpointer *user_data)
5985 {
5986 union buffered_input_event inev;
5987 struct frame *f, *frame;
5988 struct pgtk_display_info *dpyinfo;
5989
5990
5991
5992 bool tab_bar_p = false;
5993 bool tool_bar_p = false;
5994 Lisp_Object tab_bar_arg = Qnil;
5995
5996 EVENT_INIT (inev.ie);
5997 inev.ie.kind = NO_EVENT;
5998 inev.ie.arg = Qnil;
5999
6000
6001 if (event->type != GDK_BUTTON_PRESS && event->type != GDK_BUTTON_RELEASE)
6002 return TRUE;
6003
6004 frame = pgtk_any_window_to_frame (gtk_widget_get_window (widget));
6005 dpyinfo = FRAME_DISPLAY_INFO (frame);
6006
6007 dpyinfo->last_mouse_glyph_frame = NULL;
6008
6009 if (gui_mouse_grabbed (dpyinfo))
6010 f = dpyinfo->last_mouse_frame;
6011 else
6012 {
6013 f = pgtk_any_window_to_frame (gtk_widget_get_window (widget));
6014
6015 if (f && event->button.type == GDK_BUTTON_PRESS
6016 && !FRAME_NO_ACCEPT_FOCUS (f))
6017 {
6018
6019
6020
6021
6022 struct frame *hf = dpyinfo->highlight_frame;
6023
6024 if (FRAME_PARENT_FRAME (f) || (hf && frame_ancestor_p (f, hf)))
6025 {
6026 block_input ();
6027 gtk_widget_grab_focus (FRAME_GTK_WIDGET (f));
6028
6029 if (FRAME_GTK_OUTER_WIDGET (f))
6030 gtk_window_present (GTK_WINDOW (FRAME_GTK_OUTER_WIDGET (f)));
6031 unblock_input ();
6032 }
6033 }
6034 }
6035
6036
6037
6038 dpyinfo->last_user_time = event->button.time;
6039
6040 if (f)
6041 {
6042
6043 if (WINDOWP (f->tab_bar_window)
6044 && WINDOW_TOTAL_LINES (XWINDOW (f->tab_bar_window)))
6045 {
6046 Lisp_Object window;
6047 int x = event->button.x;
6048 int y = event->button.y;
6049
6050 window = window_from_coordinates (f, x, y, 0, true, true);
6051 tab_bar_p = EQ (window, f->tab_bar_window);
6052
6053 if (tab_bar_p)
6054 tab_bar_arg = handle_tab_bar_click
6055 (f, x, y, event->type == GDK_BUTTON_PRESS,
6056 pgtk_gtk_to_emacs_modifiers (dpyinfo, event->button.state));
6057 }
6058
6059 if (!(tab_bar_p && NILP (tab_bar_arg)) && !tool_bar_p)
6060 {
6061 if (ignore_next_mouse_click_timeout)
6062 {
6063 if (event->type == GDK_BUTTON_PRESS
6064 && event->button.time > ignore_next_mouse_click_timeout)
6065 {
6066 ignore_next_mouse_click_timeout = 0;
6067 construct_mouse_click (&inev.ie, &event->button, f);
6068 }
6069 if (event->type == GDK_BUTTON_RELEASE)
6070 ignore_next_mouse_click_timeout = 0;
6071 }
6072 else
6073 construct_mouse_click (&inev.ie, &event->button, f);
6074
6075 if (!NILP (tab_bar_arg))
6076 inev.ie.arg = tab_bar_arg;
6077 }
6078 }
6079
6080 if (event->type == GDK_BUTTON_PRESS)
6081 {
6082 dpyinfo->grabbed |= (1 << event->button.button);
6083 dpyinfo->last_mouse_frame = f;
6084
6085 if (dpyinfo->last_click_event != NULL)
6086 gdk_event_free (dpyinfo->last_click_event);
6087 dpyinfo->last_click_event = gdk_event_copy (event);
6088 }
6089 else
6090 dpyinfo->grabbed &= ~(1 << event->button.button);
6091
6092
6093
6094
6095 if (f != 0)
6096 f->mouse_moved = false;
6097
6098 if (inev.ie.kind != NO_EVENT)
6099 evq_enqueue (&inev);
6100 return TRUE;
6101 }
6102
6103 static gboolean
6104 scroll_event (GtkWidget *widget, GdkEvent *event, gpointer *user_data)
6105 {
6106 union buffered_input_event inev;
6107 struct frame *f, *frame;
6108 struct pgtk_display_info *dpyinfo;
6109 GdkScrollDirection dir;
6110 double delta_x, delta_y;
6111
6112 EVENT_INIT (inev.ie);
6113 inev.ie.kind = NO_EVENT;
6114 inev.ie.arg = Qnil;
6115
6116 frame = pgtk_any_window_to_frame (gtk_widget_get_window (widget));
6117 dpyinfo = FRAME_DISPLAY_INFO (frame);
6118
6119 if (gui_mouse_grabbed (dpyinfo))
6120 f = dpyinfo->last_mouse_frame;
6121 else
6122 f = pgtk_any_window_to_frame (gtk_widget_get_window (widget));
6123
6124 inev.ie.kind = NO_EVENT;
6125 inev.ie.timestamp = event->scroll.time;
6126 inev.ie.modifiers
6127 = pgtk_gtk_to_emacs_modifiers (FRAME_DISPLAY_INFO (f), event->scroll.state);
6128 XSETINT (inev.ie.x, event->scroll.x);
6129 XSETINT (inev.ie.y, event->scroll.y);
6130 XSETFRAME (inev.ie.frame_or_window, f);
6131 inev.ie.arg = Qnil;
6132
6133 if (gdk_event_is_scroll_stop_event (event))
6134 {
6135 inev.ie.kind = TOUCH_END_EVENT;
6136 inev.ie.device
6137 = pgtk_get_device_for_event (FRAME_DISPLAY_INFO (f), event);
6138 evq_enqueue (&inev);
6139 return TRUE;
6140 }
6141
6142 if (gdk_event_get_scroll_direction (event, &dir))
6143 {
6144 switch (dir)
6145 {
6146 case GDK_SCROLL_UP:
6147 inev.ie.kind = WHEEL_EVENT;
6148 inev.ie.modifiers |= up_modifier;
6149 break;
6150 case GDK_SCROLL_DOWN:
6151 inev.ie.kind = WHEEL_EVENT;
6152 inev.ie.modifiers |= down_modifier;
6153 break;
6154 case GDK_SCROLL_LEFT:
6155 inev.ie.kind = HORIZ_WHEEL_EVENT;
6156 inev.ie.modifiers |= up_modifier;
6157 break;
6158 case GDK_SCROLL_RIGHT:
6159 inev.ie.kind = HORIZ_WHEEL_EVENT;
6160 inev.ie.modifiers |= down_modifier;
6161 break;
6162 case GDK_SCROLL_SMOOTH:
6163 break;
6164 }
6165 }
6166 else if (gdk_event_get_scroll_deltas (event, &delta_x, &delta_y))
6167 {
6168 if (!mwheel_coalesce_scroll_events)
6169 {
6170 inev.ie.kind = ((fabs (delta_x) > fabs (delta_y))
6171 ? HORIZ_WHEEL_EVENT
6172 : WHEEL_EVENT);
6173 inev.ie.modifiers |= (inev.ie.kind == HORIZ_WHEEL_EVENT
6174 ? (delta_x >= 0 ? up_modifier : down_modifier)
6175 : (delta_y >= 0 ? down_modifier : up_modifier));
6176 inev.ie.arg = list3 (Qnil, make_float (-delta_x * 100),
6177 make_float (-delta_y * 100));
6178 }
6179 else
6180 {
6181 dpyinfo->scroll.acc_x += delta_x;
6182 dpyinfo->scroll.acc_y += delta_y;
6183 if (dpyinfo->scroll.acc_y >= dpyinfo->scroll.y_per_line)
6184 {
6185 int nlines = dpyinfo->scroll.acc_y / dpyinfo->scroll.y_per_line;
6186 inev.ie.kind = WHEEL_EVENT;
6187 inev.ie.modifiers |= down_modifier;
6188 inev.ie.arg = list3 (make_fixnum (nlines),
6189 make_float (-dpyinfo->scroll.acc_x * 100),
6190 make_float (-dpyinfo->scroll.acc_y * 100));
6191 dpyinfo->scroll.acc_y -= dpyinfo->scroll.y_per_line * nlines;
6192 }
6193 else if (dpyinfo->scroll.acc_y <= -dpyinfo->scroll.y_per_line)
6194 {
6195 int nlines = -dpyinfo->scroll.acc_y / dpyinfo->scroll.y_per_line;
6196 inev.ie.kind = WHEEL_EVENT;
6197 inev.ie.modifiers |= up_modifier;
6198 inev.ie.arg = list3 (make_fixnum (nlines),
6199 make_float (-dpyinfo->scroll.acc_x * 100),
6200 make_float (-dpyinfo->scroll.acc_y * 100));
6201
6202 dpyinfo->scroll.acc_y -= -dpyinfo->scroll.y_per_line * nlines;
6203 }
6204 else if (dpyinfo->scroll.acc_x >= dpyinfo->scroll.x_per_char
6205 || !mwheel_coalesce_scroll_events)
6206 {
6207 int nchars = dpyinfo->scroll.acc_x / dpyinfo->scroll.x_per_char;
6208 inev.ie.kind = HORIZ_WHEEL_EVENT;
6209 inev.ie.modifiers |= up_modifier;
6210 inev.ie.arg = list3 (make_fixnum (nchars),
6211 make_float (-dpyinfo->scroll.acc_x * 100),
6212 make_float (-dpyinfo->scroll.acc_y * 100));
6213
6214 dpyinfo->scroll.acc_x -= dpyinfo->scroll.x_per_char * nchars;
6215 }
6216 else if (dpyinfo->scroll.acc_x <= -dpyinfo->scroll.x_per_char)
6217 {
6218 int nchars = -dpyinfo->scroll.acc_x / dpyinfo->scroll.x_per_char;
6219 inev.ie.kind = HORIZ_WHEEL_EVENT;
6220 inev.ie.modifiers |= down_modifier;
6221 inev.ie.arg = list3 (make_fixnum (nchars),
6222 make_float (-dpyinfo->scroll.acc_x * 100),
6223 make_float (-dpyinfo->scroll.acc_y * 100));
6224
6225 dpyinfo->scroll.acc_x -= -dpyinfo->scroll.x_per_char * nchars;
6226 }
6227 }
6228 }
6229
6230 if (inev.ie.kind != NO_EVENT)
6231 {
6232 inev.ie.device
6233 = pgtk_get_device_for_event (FRAME_DISPLAY_INFO (f), event);
6234 evq_enqueue (&inev);
6235 }
6236 return TRUE;
6237 }
6238
6239
6240
6241
6242
6243
6244 static GdkDragAction
6245 symbol_to_drag_action (Lisp_Object act)
6246 {
6247 if (EQ (act, Qcopy))
6248 return GDK_ACTION_COPY;
6249
6250 if (EQ (act, Qmove))
6251 return GDK_ACTION_MOVE;
6252
6253 if (EQ (act, Qlink))
6254 return GDK_ACTION_LINK;
6255
6256 if (EQ (act, Qprivate))
6257 return GDK_ACTION_PRIVATE;
6258
6259 if (NILP (act))
6260 return GDK_ACTION_DEFAULT;
6261
6262 signal_error ("Invalid drag acction", act);
6263 }
6264
6265 static Lisp_Object
6266 drag_action_to_symbol (GdkDragAction action)
6267 {
6268 switch (action)
6269 {
6270 case GDK_ACTION_COPY:
6271 return Qcopy;
6272
6273 case GDK_ACTION_MOVE:
6274 return Qmove;
6275
6276 case GDK_ACTION_LINK:
6277 return Qlink;
6278
6279 case GDK_ACTION_PRIVATE:
6280 return Qprivate;
6281
6282 case GDK_ACTION_DEFAULT:
6283 default:
6284 return Qnil;
6285 }
6286 }
6287
6288 void
6289 pgtk_update_drop_status (Lisp_Object action, Lisp_Object event_time)
6290 {
6291 guint32 time;
6292
6293 CONS_TO_INTEGER (event_time, guint32, time);
6294
6295 if (!current_drop_context || time < current_drop_time)
6296 return;
6297
6298 gdk_drag_status (current_drop_context,
6299 symbol_to_drag_action (action),
6300 time);
6301 }
6302
6303 void
6304 pgtk_finish_drop (Lisp_Object success, Lisp_Object event_time,
6305 Lisp_Object del)
6306 {
6307 guint32 time;
6308
6309 CONS_TO_INTEGER (event_time, guint32, time);
6310
6311 if (!current_drop_context || time < current_drop_time)
6312 return;
6313
6314 gtk_drag_finish (current_drop_context, !NILP (success),
6315 !NILP (del), time);
6316
6317 if (current_drop_context_drop)
6318 g_clear_pointer (¤t_drop_context,
6319 g_object_unref);
6320 }
6321
6322 static void
6323 drag_leave (GtkWidget *widget, GdkDragContext *context,
6324 guint time, gpointer user_data)
6325 {
6326 struct frame *f;
6327 union buffered_input_event inev;
6328
6329 f = pgtk_any_window_to_frame (gtk_widget_get_window (widget));
6330
6331 if (current_drop_context)
6332 {
6333 if (current_drop_context_drop)
6334 gtk_drag_finish (current_drop_context,
6335 FALSE, FALSE, current_drop_time);
6336
6337 g_clear_pointer (¤t_drop_context,
6338 g_object_unref);
6339 }
6340
6341 EVENT_INIT (inev.ie);
6342
6343 inev.ie.kind = DRAG_N_DROP_EVENT;
6344 inev.ie.modifiers = 0;
6345 inev.ie.arg = Qnil;
6346 inev.ie.timestamp = time;
6347
6348 XSETINT (inev.ie.x, 0);
6349 XSETINT (inev.ie.y, 0);
6350 XSETFRAME (inev.ie.frame_or_window, f);
6351
6352 evq_enqueue (&inev);
6353 }
6354
6355 static gboolean
6356 drag_motion (GtkWidget *widget, GdkDragContext *context,
6357 gint x, gint y, guint time)
6358
6359 {
6360 struct frame *f;
6361 union buffered_input_event inev;
6362 GdkAtom name;
6363 GdkDragAction suggestion;
6364
6365 f = pgtk_any_window_to_frame (gtk_widget_get_window (widget));
6366
6367 if (!f)
6368 return FALSE;
6369
6370 if (current_drop_context)
6371 {
6372 if (current_drop_context_drop)
6373 gtk_drag_finish (current_drop_context,
6374 FALSE, FALSE, current_drop_time);
6375
6376 g_clear_pointer (¤t_drop_context,
6377 g_object_unref);
6378 }
6379
6380 current_drop_context = g_object_ref (context);
6381 current_drop_time = time;
6382 current_drop_context_drop = false;
6383
6384 name = gdk_drag_get_selection (context);
6385 suggestion = gdk_drag_context_get_suggested_action (context);
6386
6387 EVENT_INIT (inev.ie);
6388
6389 inev.ie.kind = DRAG_N_DROP_EVENT;
6390 inev.ie.modifiers = 0;
6391 inev.ie.arg = list4 (Qlambda, intern (gdk_atom_name (name)),
6392 make_uint (time),
6393 drag_action_to_symbol (suggestion));
6394 inev.ie.timestamp = time;
6395
6396 XSETINT (inev.ie.x, x);
6397 XSETINT (inev.ie.y, y);
6398 XSETFRAME (inev.ie.frame_or_window, f);
6399
6400 evq_enqueue (&inev);
6401
6402 return TRUE;
6403 }
6404
6405 static gboolean
6406 drag_drop (GtkWidget *widget, GdkDragContext *context,
6407 int x, int y, guint time, gpointer user_data)
6408 {
6409 struct frame *f;
6410 union buffered_input_event inev;
6411 GdkAtom name;
6412 GdkDragAction selected_action;
6413
6414 f = pgtk_any_window_to_frame (gtk_widget_get_window (widget));
6415
6416 if (!f)
6417 return FALSE;
6418
6419 if (current_drop_context)
6420 {
6421 if (current_drop_context_drop)
6422 gtk_drag_finish (current_drop_context,
6423 FALSE, FALSE, current_drop_time);
6424
6425 g_clear_pointer (¤t_drop_context,
6426 g_object_unref);
6427 }
6428
6429 current_drop_context = g_object_ref (context);
6430 current_drop_time = time;
6431 current_drop_context_drop = true;
6432
6433 name = gdk_drag_get_selection (context);
6434 selected_action = gdk_drag_context_get_selected_action (context);
6435
6436 EVENT_INIT (inev.ie);
6437
6438 inev.ie.kind = DRAG_N_DROP_EVENT;
6439 inev.ie.modifiers = 0;
6440 inev.ie.arg = list4 (Qquote, intern (gdk_atom_name (name)),
6441 make_uint (time),
6442 drag_action_to_symbol (selected_action));
6443 inev.ie.timestamp = time;
6444
6445 XSETINT (inev.ie.x, x);
6446 XSETINT (inev.ie.y, y);
6447 XSETFRAME (inev.ie.frame_or_window, f);
6448
6449 evq_enqueue (&inev);
6450
6451 return TRUE;
6452 }
6453
6454 static void
6455 pgtk_monitors_changed_cb (GdkScreen *screen, gpointer user_data)
6456 {
6457 struct terminal *terminal;
6458 union buffered_input_event inev;
6459
6460 EVENT_INIT (inev.ie);
6461 terminal = user_data;
6462 inev.ie.kind = MONITORS_CHANGED_EVENT;
6463 XSETTERMINAL (inev.ie.arg, terminal);
6464
6465 evq_enqueue (&inev);
6466 }
6467
6468 static gboolean pgtk_selection_event (GtkWidget *, GdkEvent *, gpointer);
6469
6470 void
6471 pgtk_set_event_handler (struct frame *f)
6472 {
6473 if (f->tooltip)
6474 {
6475 g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "draw",
6476 G_CALLBACK (pgtk_handle_draw), NULL);
6477 return;
6478 }
6479
6480 gtk_drag_dest_set (FRAME_GTK_WIDGET (f), 0, NULL, 0,
6481 (GDK_ACTION_MOVE | GDK_ACTION_COPY
6482 | GDK_ACTION_LINK | GDK_ACTION_PRIVATE));
6483
6484 if (FRAME_GTK_OUTER_WIDGET (f))
6485 {
6486 g_signal_connect (G_OBJECT (FRAME_GTK_OUTER_WIDGET (f)),
6487 "window-state-event", G_CALLBACK (window_state_event),
6488 NULL);
6489 g_signal_connect (G_OBJECT (FRAME_GTK_OUTER_WIDGET (f)), "delete-event",
6490 G_CALLBACK (delete_event), NULL);
6491 g_signal_connect (G_OBJECT (FRAME_GTK_OUTER_WIDGET (f)), "event",
6492 G_CALLBACK (pgtk_handle_event), NULL);
6493 g_signal_connect (G_OBJECT (FRAME_GTK_OUTER_WIDGET (f)), "configure-event",
6494 G_CALLBACK (configure_event), NULL);
6495 }
6496
6497 g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "map-event",
6498 G_CALLBACK (map_event), NULL);
6499 g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "size-allocate",
6500 G_CALLBACK (size_allocate), f);
6501 g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "key-press-event",
6502 G_CALLBACK (key_press_event), NULL);
6503 g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "key-release-event",
6504 G_CALLBACK (key_release_event), NULL);
6505 g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "focus-in-event",
6506 G_CALLBACK (focus_in_event), NULL);
6507 g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "focus-out-event",
6508 G_CALLBACK (focus_out_event), NULL);
6509 g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "enter-notify-event",
6510 G_CALLBACK (enter_notify_event), NULL);
6511 g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "leave-notify-event",
6512 G_CALLBACK (leave_notify_event), NULL);
6513 g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "motion-notify-event",
6514 G_CALLBACK (motion_notify_event), NULL);
6515 g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "button-press-event",
6516 G_CALLBACK (button_event), NULL);
6517 g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "button-release-event",
6518 G_CALLBACK (button_event), NULL);
6519 g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "scroll-event",
6520 G_CALLBACK (scroll_event), NULL);
6521 g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "configure-event",
6522 G_CALLBACK (configure_event), NULL);
6523 g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "drag-leave",
6524 G_CALLBACK (drag_leave), NULL);
6525 g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "drag-motion",
6526 G_CALLBACK (drag_motion), NULL);
6527 g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "drag-drop",
6528 G_CALLBACK (drag_drop), NULL);
6529 g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "draw",
6530 G_CALLBACK (pgtk_handle_draw), NULL);
6531 g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "property-notify-event",
6532 G_CALLBACK (pgtk_selection_event), NULL);
6533 g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "selection-clear-event",
6534 G_CALLBACK (pgtk_selection_event), NULL);
6535 g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "selection-request-event",
6536 G_CALLBACK (pgtk_selection_event), NULL);
6537 g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "selection-notify-event",
6538 G_CALLBACK (pgtk_selection_event), NULL);
6539 g_signal_connect (G_OBJECT (FRAME_GTK_WIDGET (f)), "event",
6540 G_CALLBACK (pgtk_handle_event), NULL);
6541 }
6542
6543 static void
6544 my_log_handler (const gchar * log_domain, GLogLevelFlags log_level,
6545 const gchar * msg, gpointer user_data)
6546 {
6547 if (!strstr (msg, "g_set_prgname"))
6548 fprintf (stderr, "%s-WARNING **: %s", log_domain, msg);
6549 }
6550
6551
6552
6553 static bool
6554 same_x_server (const char *name1, const char *name2)
6555 {
6556 bool seen_colon = false;
6557 Lisp_Object sysname = Fsystem_name ();
6558 const char *system_name = SSDATA (sysname);
6559 ptrdiff_t system_name_length = SBYTES (sysname);
6560 ptrdiff_t length_until_period = 0;
6561
6562 while (system_name[length_until_period] != 0
6563 && system_name[length_until_period] != '.')
6564 length_until_period++;
6565
6566
6567 if (!strncmp (name1, "unix:", 5))
6568 name1 += 4;
6569 if (!strncmp (name2, "unix:", 5))
6570 name2 += 4;
6571
6572 if (!strncmp (name1, system_name, system_name_length)
6573 && name1[system_name_length] == ':')
6574 name1 += system_name_length;
6575 if (!strncmp (name2, system_name, system_name_length)
6576 && name2[system_name_length] == ':')
6577 name2 += system_name_length;
6578
6579 if (!strncmp (name1, system_name, length_until_period)
6580 && name1[length_until_period] == ':')
6581 name1 += length_until_period;
6582 if (!strncmp (name2, system_name, length_until_period)
6583 && name2[length_until_period] == ':')
6584 name2 += length_until_period;
6585
6586 for (; *name1 != '\0' && *name1 == *name2; name1++, name2++)
6587 {
6588 if (*name1 == ':')
6589 seen_colon = true;
6590 if (seen_colon && *name1 == '.')
6591 return true;
6592 }
6593 return (seen_colon
6594 && (*name1 == '.' || *name1 == '\0')
6595 && (*name2 == '.' || *name2 == '\0'));
6596 }
6597
6598 static struct frame *
6599 pgtk_find_selection_owner (GdkWindow *window)
6600 {
6601 Lisp_Object tail, tem;
6602 struct frame *f;
6603
6604 FOR_EACH_FRAME (tail, tem)
6605 {
6606 f = XFRAME (tem);
6607
6608 if (FRAME_PGTK_P (f)
6609 && (FRAME_GDK_WINDOW (f) == window))
6610 return f;
6611 }
6612
6613 return NULL;
6614 }
6615
6616 static gboolean
6617 pgtk_selection_event (GtkWidget *widget, GdkEvent *event,
6618 gpointer user_data)
6619 {
6620 struct frame *f;
6621 union buffered_input_event inev;
6622
6623 if (event->type == GDK_PROPERTY_NOTIFY)
6624 pgtk_handle_property_notify (&event->property);
6625 else if (event->type == GDK_SELECTION_CLEAR
6626 || event->type == GDK_SELECTION_REQUEST)
6627 {
6628 f = pgtk_find_selection_owner (event->selection.window);
6629
6630 if (f)
6631 {
6632 EVENT_INIT (inev.ie);
6633
6634 inev.sie.kind = (event->type == GDK_SELECTION_CLEAR
6635 ? SELECTION_CLEAR_EVENT
6636 : SELECTION_REQUEST_EVENT);
6637
6638 SELECTION_EVENT_DPYINFO (&inev.sie) = FRAME_DISPLAY_INFO (f);
6639 SELECTION_EVENT_SELECTION (&inev.sie) = event->selection.selection;
6640 SELECTION_EVENT_TIME (&inev.sie) = event->selection.time;
6641
6642 if (event->type == GDK_SELECTION_REQUEST)
6643 {
6644
6645
6646
6647
6648
6649
6650 SELECTION_EVENT_REQUESTOR (&inev.sie) = event->selection.requestor;
6651 SELECTION_EVENT_TARGET (&inev.sie) = event->selection.target;
6652 SELECTION_EVENT_PROPERTY (&inev.sie) = event->selection.property;
6653 }
6654
6655 evq_enqueue (&inev);
6656 return TRUE;
6657 }
6658 }
6659 else if (event->type == GDK_SELECTION_NOTIFY)
6660 pgtk_handle_selection_notify (&event->selection);
6661
6662 return FALSE;
6663 }
6664
6665
6666
6667
6668 static void
6669 pgtk_display_x_warning (GdkDisplay *display)
6670 {
6671 GtkWidget *dialog_widget, *label, *content_area;
6672 GtkDialog *dialog;
6673 GtkWindow *window;
6674 GdkScreen *screen;
6675
6676
6677
6678 if (strcmp (G_OBJECT_TYPE_NAME (display),
6679 "GdkX11Display"))
6680 return;
6681
6682 dialog_widget = gtk_dialog_new ();
6683 dialog = GTK_DIALOG (dialog_widget);
6684 window = GTK_WINDOW (dialog_widget);
6685 screen = gdk_display_get_default_screen (display);
6686 content_area = gtk_dialog_get_content_area (dialog);
6687
6688 gtk_window_set_title (window, "Warning");
6689 gtk_window_set_screen (window, screen);
6690
6691 label = gtk_label_new ("You are trying to run Emacs configured with\n"
6692 " the \"pure-GTK\" interface under the X Window\n"
6693 " System. That configuration is unsupported and\n"
6694 " will lead to sporadic crashes during transfer of\n"
6695 " large selection data. It will also lead to\n"
6696 " various problems with keyboard input.\n");
6697 gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
6698 gtk_container_add (GTK_CONTAINER (content_area), label);
6699 gtk_widget_show (label);
6700 gtk_widget_show (dialog_widget);
6701 }
6702
6703
6704
6705
6706
6707 struct pgtk_display_info *
6708 pgtk_term_init (Lisp_Object display_name, char *resource_name)
6709 {
6710 GdkDisplay *dpy;
6711 struct terminal *terminal;
6712 struct pgtk_display_info *dpyinfo;
6713 static int x_initialized = 0;
6714 static unsigned x_display_id = 0;
6715 static char *initial_display = NULL;
6716 char *dpy_name;
6717 static void *handle = NULL;
6718 Lisp_Object lisp_dpy_name = Qnil;
6719 GdkScreen *gscr;
6720 gdouble dpi;
6721
6722 block_input ();
6723
6724 if (!x_initialized)
6725 {
6726 any_help_event_p = false;
6727
6728 Fset_input_interrupt_mode (Qt);
6729 baud_rate = 19200;
6730
6731 #ifdef USE_CAIRO
6732 gui_init_fringe (&pgtk_redisplay_interface);
6733 #endif
6734
6735 ++x_initialized;
6736 }
6737
6738 dpy_name = SSDATA (display_name);
6739 if (strlen (dpy_name) == 0 && initial_display != NULL)
6740 dpy_name = initial_display;
6741 lisp_dpy_name = build_string (dpy_name);
6742
6743 {
6744 #define NUM_ARGV 10
6745 int argc;
6746 char *argv[NUM_ARGV];
6747 char **argv2 = argv;
6748 guint id;
6749
6750 if (x_initialized++ > 1)
6751 {
6752 xg_display_open (dpy_name, &dpy);
6753 }
6754 else
6755 {
6756 static char display_opt[] = "--display";
6757 static char name_opt[] = "--name";
6758
6759 for (argc = 0; argc < NUM_ARGV; ++argc)
6760 argv[argc] = 0;
6761
6762 argc = 0;
6763 argv[argc++] = initial_argv[0];
6764
6765 if (strlen (dpy_name) != 0)
6766 {
6767 argv[argc++] = display_opt;
6768 argv[argc++] = dpy_name;
6769 }
6770
6771 argv[argc++] = name_opt;
6772 argv[argc++] = resource_name;
6773
6774
6775
6776 id = g_log_set_handler ("GLib", G_LOG_LEVEL_WARNING | G_LOG_FLAG_FATAL
6777 | G_LOG_FLAG_RECURSION, my_log_handler, NULL);
6778
6779
6780 fixup_locale ();
6781 unrequest_sigio ();
6782 gtk_init (&argc, &argv2);
6783 request_sigio ();
6784 fixup_locale ();
6785
6786
6787 g_log_remove_handler ("GLib", id);
6788
6789 xg_initialize ();
6790
6791 dpy = DEFAULT_GDK_DISPLAY ();
6792
6793 initial_display = g_strdup (gdk_display_get_name (dpy));
6794 dpy_name = initial_display;
6795 lisp_dpy_name = build_string (dpy_name);
6796 }
6797 }
6798
6799
6800 if (dpy == 0)
6801 {
6802 unblock_input ();
6803 return 0;
6804 }
6805
6806
6807
6808 pgtk_display_x_warning (dpy);
6809
6810 dpyinfo = xzalloc (sizeof *dpyinfo);
6811 pgtk_initialize_display_info (dpyinfo);
6812 terminal = pgtk_create_terminal (dpyinfo);
6813
6814 {
6815 struct pgtk_display_info *share;
6816
6817 for (share = x_display_list; share; share = share->next)
6818 if (same_x_server (SSDATA (XCAR (share->name_list_element)), dpy_name))
6819 break;
6820 if (share)
6821 terminal->kboard = share->terminal->kboard;
6822 else
6823 {
6824 terminal->kboard = allocate_kboard (Qpgtk);
6825
6826
6827
6828
6829 if (current_kboard == initial_kboard)
6830 current_kboard = terminal->kboard;
6831 }
6832 terminal->kboard->reference_count++;
6833 }
6834
6835
6836 dpyinfo->next = x_display_list;
6837 x_display_list = dpyinfo;
6838
6839 dpyinfo->name_list_element = Fcons (lisp_dpy_name, Qnil);
6840 dpyinfo->gdpy = dpy;
6841
6842
6843 dpyinfo->smallest_font_height = 1;
6844 dpyinfo->smallest_char_width = 1;
6845
6846
6847 terminal->name = xlispstrdup (lisp_dpy_name);
6848
6849 Lisp_Object system_name = Fsystem_name ();
6850 ptrdiff_t nbytes;
6851 if (ckd_add (&nbytes, SBYTES (Vinvocation_name), SBYTES (system_name) + 2))
6852 memory_full (SIZE_MAX);
6853 dpyinfo->x_id = ++x_display_id;
6854 dpyinfo->x_id_name = xmalloc (nbytes);
6855 char *nametail = lispstpcpy (dpyinfo->x_id_name, Vinvocation_name);
6856 *nametail++ = '@';
6857 lispstpcpy (nametail, system_name);
6858
6859
6860
6861 dpyinfo->xg_cursor = xg_create_default_cursor (dpyinfo->gdpy);
6862
6863 dpyinfo->vertical_scroll_bar_cursor
6864 = gdk_cursor_new_for_display (dpyinfo->gdpy, GDK_SB_V_DOUBLE_ARROW);
6865
6866 dpyinfo->horizontal_scroll_bar_cursor
6867 = gdk_cursor_new_for_display (dpyinfo->gdpy, GDK_SB_H_DOUBLE_ARROW);
6868
6869 dpyinfo->icon_bitmap_id = -1;
6870
6871 reset_mouse_highlight (&dpyinfo->mouse_highlight);
6872
6873 gscr = gdk_display_get_default_screen (dpyinfo->gdpy);
6874 dpi = gdk_screen_get_resolution (gscr);
6875
6876 if (dpi < 0)
6877 dpi = 96.0;
6878
6879 dpyinfo->resx = dpi;
6880 dpyinfo->resy = dpi;
6881
6882 g_signal_connect (G_OBJECT (gscr), "monitors-changed",
6883 G_CALLBACK (pgtk_monitors_changed_cb),
6884 terminal);
6885
6886
6887 dpyinfo->scroll.x_per_char = 1;
6888 dpyinfo->scroll.y_per_line = 1;
6889
6890 dpyinfo->connection = -1;
6891
6892 if (!handle)
6893 handle = dlopen (NULL, RTLD_LAZY);
6894
6895 #ifdef GDK_WINDOWING_X11
6896 if (!strcmp (G_OBJECT_TYPE_NAME (dpy), "GdkX11Display") && handle)
6897 {
6898 void *(*gdk_x11_display_get_xdisplay) (GdkDisplay *)
6899 = dlsym (handle, "gdk_x11_display_get_xdisplay");
6900 int (*x_connection_number) (void *)
6901 = dlsym (handle, "XConnectionNumber");
6902
6903 if (x_connection_number
6904 && gdk_x11_display_get_xdisplay)
6905 dpyinfo->connection
6906 = x_connection_number (gdk_x11_display_get_xdisplay (dpy));
6907 }
6908 #endif
6909
6910 #ifdef GDK_WINDOWING_WAYLAND
6911 if (GDK_IS_WAYLAND_DISPLAY (dpy) && handle)
6912 {
6913 struct wl_display *wl_dpy = gdk_wayland_display_get_wl_display (dpy);
6914 int (*display_get_fd) (struct wl_display *)
6915 = dlsym (handle, "wl_display_get_fd");
6916
6917 if (display_get_fd)
6918 dpyinfo->connection = display_get_fd (wl_dpy);
6919 }
6920 #endif
6921
6922 if (dpyinfo->connection >= 0)
6923 {
6924 add_keyboard_wait_descriptor (dpyinfo->connection);
6925 #ifdef F_SETOWN
6926 fcntl (dpyinfo->connection, F_SETOWN, getpid ());
6927 #endif
6928
6929 if (interrupt_input)
6930 init_sigio (dpyinfo->connection);
6931 }
6932
6933 dpyinfo->invisible_cursor
6934 = gdk_cursor_new_for_display (dpyinfo->gdpy, GDK_BLANK_CURSOR);
6935
6936 xsettings_initialize (dpyinfo);
6937
6938 pgtk_im_init (dpyinfo);
6939
6940 g_signal_connect (G_OBJECT (dpyinfo->gdpy), "seat-added",
6941 G_CALLBACK (pgtk_seat_added_cb), dpyinfo);
6942 g_signal_connect (G_OBJECT (dpyinfo->gdpy), "seat-removed",
6943 G_CALLBACK (pgtk_seat_removed_cb), dpyinfo);
6944 pgtk_enumerate_devices (dpyinfo, true);
6945
6946 unblock_input ();
6947
6948 return dpyinfo;
6949 }
6950
6951
6952
6953
6954 static void
6955 pgtk_delete_display (struct pgtk_display_info *dpyinfo)
6956 {
6957 struct terminal *t;
6958
6959
6960
6961 for (t = terminal_list; t; t = t->next_terminal)
6962 if (t->type == output_pgtk && t->display_info.pgtk == dpyinfo)
6963 {
6964 delete_terminal (t);
6965 break;
6966 }
6967
6968 if (x_display_list == dpyinfo)
6969 x_display_list = dpyinfo->next;
6970 else
6971 {
6972 struct pgtk_display_info *tail;
6973
6974 for (tail = x_display_list; tail; tail = tail->next)
6975 if (tail->next == dpyinfo)
6976 tail->next = tail->next->next;
6977 }
6978
6979 pgtk_free_devices (dpyinfo);
6980 xfree (dpyinfo);
6981 }
6982
6983 char *
6984 pgtk_xlfd_to_fontname (const char *xlfd)
6985
6986
6987
6988
6989
6990 {
6991 char *name = xmalloc (180);
6992
6993 if (!strncmp (xlfd, "--", 2))
6994 {
6995 if (sscanf (xlfd, "--%179[^-]-", name) != 1)
6996 name[0] = '\0';
6997 }
6998 else
6999 {
7000 if (sscanf (xlfd, "-%*[^-]-%179[^-]-", name) != 1)
7001 name[0] = '\0';
7002 }
7003
7004
7005 if (strlen (name) == 0)
7006 strcpy (name, "Monospace");
7007
7008 return name;
7009 }
7010
7011 bool
7012 pgtk_defined_color (struct frame *f, const char *name,
7013 Emacs_Color *color_def, bool alloc,
7014 bool makeIndex)
7015
7016
7017
7018
7019
7020
7021
7022 {
7023 int r;
7024
7025 block_input ();
7026 r = xg_check_special_colors (f, name, color_def);
7027 if (!r)
7028 r = pgtk_parse_color (f, name, color_def);
7029 unblock_input ();
7030 return r;
7031 }
7032
7033
7034
7035
7036
7037
7038
7039
7040
7041 int
7042 pgtk_parse_color (struct frame *f, const char *color_name,
7043 Emacs_Color * color)
7044 {
7045 GdkRGBA rgba;
7046 if (gdk_rgba_parse (&rgba, color_name))
7047 {
7048 color->red = rgba.red * 65535;
7049 color->green = rgba.green * 65535;
7050 color->blue = rgba.blue * 65535;
7051 color->pixel = ((color->red >> 8) << 16
7052 | (color->green >> 8) << 8
7053 | (color->blue >> 8) << 0);
7054 return 1;
7055 }
7056 return 0;
7057 }
7058
7059
7060
7061
7062 void
7063 pgtk_query_colors (struct frame *f, Emacs_Color * colors, int ncolors)
7064 {
7065 int i;
7066
7067 for (i = 0; i < ncolors; i++)
7068 {
7069 unsigned long pixel = colors[i].pixel;
7070
7071 #define GetRValue(p) (((p) >> 16) & 0xff)
7072 #define GetGValue(p) (((p) >> 8) & 0xff)
7073 #define GetBValue(p) (((p) >> 0) & 0xff)
7074 colors[i].red = GetRValue (pixel) * 257;
7075 colors[i].green = GetGValue (pixel) * 257;
7076 colors[i].blue = GetBValue (pixel) * 257;
7077 }
7078 }
7079
7080 void
7081 pgtk_query_color (struct frame *f, Emacs_Color * color)
7082 {
7083 pgtk_query_colors (f, color, 1);
7084 }
7085
7086 void
7087 pgtk_clear_area (struct frame *f, int x, int y, int width, int height)
7088 {
7089 cairo_t *cr;
7090
7091 eassert (width > 0 && height > 0);
7092
7093 cr = pgtk_begin_cr_clip (f);
7094 pgtk_set_cr_source_with_color (f, FRAME_X_OUTPUT (f)->background_color,
7095 true);
7096 cairo_rectangle (cr, x, y, width, height);
7097 cairo_fill (cr);
7098 pgtk_end_cr_clip (f);
7099 }
7100
7101
7102 void
7103 syms_of_pgtkterm (void)
7104 {
7105 DEFSYM (Qmodifier_value, "modifier-value");
7106 DEFSYM (Qalt, "alt");
7107 DEFSYM (Qhyper, "hyper");
7108 DEFSYM (Qmeta, "meta");
7109 DEFSYM (Qsuper, "super");
7110 DEFSYM (Qcontrol, "control");
7111 DEFSYM (QUTF8_STRING, "UTF8_STRING");
7112
7113 DEFSYM (Qfile, "file");
7114 DEFSYM (Qurl, "url");
7115
7116 DEFSYM (Qlatin_1, "latin-1");
7117
7118 xg_default_icon_file
7119 = build_pure_c_string ("icons/hicolor/scalable/apps/emacs.svg");
7120 staticpro (&xg_default_icon_file);
7121
7122 DEFSYM (Qx_gtk_map_stock, "x-gtk-map-stock");
7123
7124 DEFSYM (Qcopy, "copy");
7125 DEFSYM (Qmove, "move");
7126 DEFSYM (Qlink, "link");
7127 DEFSYM (Qprivate, "private");
7128
7129
7130 Fput (Qalt, Qmodifier_value, make_fixnum (alt_modifier));
7131 Fput (Qhyper, Qmodifier_value, make_fixnum (hyper_modifier));
7132 Fput (Qmeta, Qmodifier_value, make_fixnum (meta_modifier));
7133 Fput (Qsuper, Qmodifier_value, make_fixnum (super_modifier));
7134 Fput (Qcontrol, Qmodifier_value, make_fixnum (ctrl_modifier));
7135
7136 DEFVAR_LISP ("x-ctrl-keysym", Vx_ctrl_keysym,
7137 doc: );
7138 Vx_ctrl_keysym = Qnil;
7139
7140 DEFVAR_LISP ("x-alt-keysym", Vx_alt_keysym,
7141 doc: );
7142 Vx_alt_keysym = Qnil;
7143
7144 DEFVAR_LISP ("x-hyper-keysym", Vx_hyper_keysym,
7145 doc: );
7146 Vx_hyper_keysym = Qnil;
7147
7148 DEFVAR_LISP ("x-meta-keysym", Vx_meta_keysym,
7149 doc: );
7150 Vx_meta_keysym = Qnil;
7151
7152 DEFVAR_LISP ("x-super-keysym", Vx_super_keysym,
7153 doc: );
7154 Vx_super_keysym = Qnil;
7155
7156 DEFVAR_BOOL ("x-use-underline-position-properties",
7157 x_use_underline_position_properties,
7158 doc: );
7159 x_use_underline_position_properties = 1;
7160
7161 DEFVAR_BOOL ("x-underline-at-descent-line",
7162 x_underline_at_descent_line,
7163 doc: );
7164 x_underline_at_descent_line = 0;
7165
7166 DEFVAR_LISP ("x-toolkit-scroll-bars", Vx_toolkit_scroll_bars,
7167 doc: );
7168 Vx_toolkit_scroll_bars = intern_c_string ("gtk");
7169
7170 DEFVAR_LISP ("pgtk-wait-for-event-timeout", Vpgtk_wait_for_event_timeout,
7171 doc:
7172
7173
7174
7175
7176
7177
7178 );
7179 Vpgtk_wait_for_event_timeout = make_float (0.1);
7180
7181 DEFVAR_LISP ("pgtk-keysym-table", Vpgtk_keysym_table,
7182 doc: );
7183 Vpgtk_keysym_table = make_hash_table (hashtest_eql, 900, DEFAULT_REHASH_SIZE,
7184 DEFAULT_REHASH_THRESHOLD, Qnil, false);
7185
7186 window_being_scrolled = Qnil;
7187 staticpro (&window_being_scrolled);
7188
7189
7190 Fprovide (Qpgtk, Qnil);
7191 }
7192
7193
7194
7195
7196
7197
7198
7199
7200 void
7201 pgtk_cr_update_surface_desired_size (struct frame *f, int width, int height, bool force)
7202 {
7203 if (FRAME_CR_SURFACE_DESIRED_WIDTH (f) != width
7204 || FRAME_CR_SURFACE_DESIRED_HEIGHT (f) != height
7205 || force)
7206 {
7207 pgtk_cr_destroy_frame_context (f);
7208 FRAME_CR_SURFACE_DESIRED_WIDTH (f) = width;
7209 FRAME_CR_SURFACE_DESIRED_HEIGHT (f) = height;
7210 SET_FRAME_GARBAGED (f);
7211 }
7212 }
7213
7214
7215 cairo_t *
7216 pgtk_begin_cr_clip (struct frame *f)
7217 {
7218 cairo_t *cr = FRAME_CR_CONTEXT (f);
7219
7220 if (!cr)
7221 {
7222 cairo_surface_t *surface
7223 = gdk_window_create_similar_surface (gtk_widget_get_window
7224 (FRAME_GTK_WIDGET (f)),
7225 CAIRO_CONTENT_COLOR_ALPHA,
7226 FRAME_CR_SURFACE_DESIRED_WIDTH (f),
7227 FRAME_CR_SURFACE_DESIRED_HEIGHT
7228 (f));
7229
7230 cr = FRAME_CR_CONTEXT (f) = cairo_create (surface);
7231 cairo_surface_destroy (surface);
7232 }
7233
7234 cairo_save (cr);
7235
7236 return cr;
7237 }
7238
7239 void
7240 pgtk_end_cr_clip (struct frame *f)
7241 {
7242 cairo_restore (FRAME_CR_CONTEXT (f));
7243 }
7244
7245 void
7246 pgtk_set_cr_source_with_gc_foreground (struct frame *f, Emacs_GC *gc,
7247 bool respects_alpha_background)
7248 {
7249 pgtk_set_cr_source_with_color (f, gc->foreground,
7250 respects_alpha_background);
7251 }
7252
7253 void
7254 pgtk_set_cr_source_with_gc_background (struct frame *f, Emacs_GC *gc,
7255 bool respects_alpha_background)
7256 {
7257 pgtk_set_cr_source_with_color (f, gc->background,
7258 respects_alpha_background);
7259 }
7260
7261 void
7262 pgtk_set_cr_source_with_color (struct frame *f, unsigned long color,
7263 bool respects_alpha_background)
7264 {
7265 Emacs_Color col;
7266 col.pixel = color;
7267 pgtk_query_color (f, &col);
7268
7269 if (!respects_alpha_background)
7270 {
7271 cairo_set_source_rgb (FRAME_CR_CONTEXT (f), col.red / 65535.0,
7272 col.green / 65535.0, col.blue / 65535.0);
7273 cairo_set_operator (FRAME_CR_CONTEXT (f), CAIRO_OPERATOR_OVER);
7274 }
7275 else
7276 {
7277 cairo_set_source_rgba (FRAME_CR_CONTEXT (f), col.red / 65535.0,
7278 col.green / 65535.0, col.blue / 65535.0,
7279 f->alpha_background);
7280 cairo_set_operator (FRAME_CR_CONTEXT (f), CAIRO_OPERATOR_SOURCE);
7281 }
7282 }
7283
7284 void
7285 pgtk_cr_draw_frame (cairo_t * cr, struct frame *f)
7286 {
7287 cairo_set_source_surface (cr, FRAME_CR_SURFACE (f), 0, 0);
7288 cairo_paint (cr);
7289 }
7290
7291 static cairo_status_t
7292 pgtk_cr_accumulate_data (void *closure, const unsigned char *data,
7293 unsigned int length)
7294 {
7295 Lisp_Object *acc = (Lisp_Object *) closure;
7296
7297 *acc = Fcons (make_unibyte_string ((char const *) data, length), *acc);
7298
7299 return CAIRO_STATUS_SUCCESS;
7300 }
7301
7302 void
7303 pgtk_cr_destroy_frame_context (struct frame *f)
7304 {
7305 if (FRAME_CR_CONTEXT (f) != NULL)
7306 {
7307 cairo_destroy (FRAME_CR_CONTEXT (f));
7308 FRAME_CR_CONTEXT (f) = NULL;
7309 }
7310 }
7311
7312 static void
7313 pgtk_cr_destroy (void *cr)
7314 {
7315 block_input ();
7316 cairo_destroy (cr);
7317 unblock_input ();
7318 }
7319
7320 Lisp_Object
7321 pgtk_cr_export_frames (Lisp_Object frames, cairo_surface_type_t surface_type)
7322 {
7323 struct frame *f;
7324 cairo_surface_t *surface;
7325 cairo_t *cr;
7326 int width, height;
7327 void (*surface_set_size_func) (cairo_surface_t *, double, double) = NULL;
7328 Lisp_Object acc = Qnil;
7329 specpdl_ref count = SPECPDL_INDEX ();
7330
7331 specbind (Qredisplay_dont_pause, Qt);
7332 redisplay_preserve_echo_area (31);
7333
7334 f = XFRAME (XCAR (frames));
7335 frames = XCDR (frames);
7336 width = FRAME_PIXEL_WIDTH (f);
7337 height = FRAME_PIXEL_HEIGHT (f);
7338
7339 block_input ();
7340 #ifdef CAIRO_HAS_PDF_SURFACE
7341 if (surface_type == CAIRO_SURFACE_TYPE_PDF)
7342 {
7343 surface = cairo_pdf_surface_create_for_stream (pgtk_cr_accumulate_data, &acc,
7344 width, height);
7345 surface_set_size_func = cairo_pdf_surface_set_size;
7346 }
7347 else
7348 #endif
7349 #ifdef CAIRO_HAS_PNG_FUNCTIONS
7350 if (surface_type == CAIRO_SURFACE_TYPE_IMAGE)
7351 surface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, width, height);
7352 else
7353 #endif
7354 #ifdef CAIRO_HAS_PS_SURFACE
7355 if (surface_type == CAIRO_SURFACE_TYPE_PS)
7356 {
7357 surface = cairo_ps_surface_create_for_stream (pgtk_cr_accumulate_data, &acc,
7358 width, height);
7359 surface_set_size_func = cairo_ps_surface_set_size;
7360 }
7361 else
7362 #endif
7363 #ifdef CAIRO_HAS_SVG_SURFACE
7364 if (surface_type == CAIRO_SURFACE_TYPE_SVG)
7365 surface = cairo_svg_surface_create_for_stream (pgtk_cr_accumulate_data, &acc,
7366 width, height);
7367 else
7368 #endif
7369 abort ();
7370
7371 cr = cairo_create (surface);
7372 cairo_surface_destroy (surface);
7373 record_unwind_protect_ptr (pgtk_cr_destroy, cr);
7374
7375 while (1)
7376 {
7377 cairo_t *saved_cr = FRAME_CR_CONTEXT (f);
7378 FRAME_CR_CONTEXT (f) = cr;
7379 pgtk_clear_area (f, 0, 0, width, height);
7380 expose_frame (f, 0, 0, width, height);
7381 FRAME_CR_CONTEXT (f) = saved_cr;
7382
7383 if (NILP (frames))
7384 break;
7385
7386 cairo_surface_show_page (surface);
7387 f = XFRAME (XCAR (frames));
7388 frames = XCDR (frames);
7389 width = FRAME_PIXEL_WIDTH (f);
7390 height = FRAME_PIXEL_HEIGHT (f);
7391 if (surface_set_size_func)
7392 (*surface_set_size_func) (surface, width, height);
7393
7394 unblock_input ();
7395 maybe_quit ();
7396 block_input ();
7397 }
7398
7399 #ifdef CAIRO_HAS_PNG_FUNCTIONS
7400 if (surface_type == CAIRO_SURFACE_TYPE_IMAGE)
7401 {
7402 cairo_surface_flush (surface);
7403 cairo_surface_write_to_png_stream (surface, pgtk_cr_accumulate_data, &acc);
7404 }
7405 #endif
7406 unblock_input ();
7407
7408 unbind_to (count, Qnil);
7409
7410 return CALLN (Fapply, intern ("concat"), Fnreverse (acc));
7411 }