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