aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorYuuki Harano2019-07-07 02:24:14 +0900
committerJeff Walsh2020-11-22 14:46:55 +1100
commitfbba846ee8d63304385b59e8f6a553398b533345 (patch)
treedbb8d888648ff228b5b222865c78799ae9adbcca /src
parent85441c96d74f82ca368b950aa0f5334297bf4fa0 (diff)
downloademacs-fbba846ee8d63304385b59e8f6a553398b533345.tar.gz
emacs-fbba846ee8d63304385b59e8f6a553398b533345.zip
Addframe highlighting support
* ../src/pgtkterm.c: (pgtk_focus_frame, set_opacity_recursively, x_set_frame_alpha) (frame_highlight, frame_unhighlight, pgtk_frame_rehighlight) (XTframe_rehighlight, x_new_focus_frame, pgtk_create_terminal): frame の highlight に対応。 とりあえず opacity のみ対応。
Diffstat (limited to 'src')
-rw-r--r--src/pgtkterm.c316
-rw-r--r--src/pgtkterm.h1
2 files changed, 187 insertions, 130 deletions
diff --git a/src/pgtkterm.c b/src/pgtkterm.c
index fb2520614f2..1c2f0c96487 100644
--- a/src/pgtkterm.c
+++ b/src/pgtkterm.c
@@ -4351,6 +4351,190 @@ pgtk_free_pixmap (struct frame *_f, Emacs_Pixmap pixmap)
4351 } 4351 }
4352} 4352}
4353 4353
4354void
4355pgtk_focus_frame (struct frame *f, bool noactivate)
4356{
4357 struct pgtk_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
4358
4359 GtkWidget *wid = FRAME_GTK_OUTER_WIDGET(f);
4360
4361 if (dpyinfo->x_focus_frame != f)
4362 {
4363 block_input ();
4364 gtk_window_present (GTK_WINDOW (wid));
4365 unblock_input ();
4366 }
4367}
4368
4369
4370static void set_opacity_recursively (GtkWidget *w, gpointer data)
4371{
4372 gtk_widget_set_opacity (w, *(double *) data);
4373 if (GTK_IS_CONTAINER (w))
4374 gtk_container_foreach (GTK_CONTAINER (w), set_opacity_recursively, data);
4375}
4376
4377static void
4378x_set_frame_alpha (struct frame *f)
4379{
4380 struct pgtk_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
4381 double alpha = 1.0;
4382 double alpha_min = 1.0;
4383
4384 if (dpyinfo->highlight_frame == f)
4385 alpha = f->alpha[0];
4386 else
4387 alpha = f->alpha[1];
4388
4389 if (alpha < 0.0)
4390 return;
4391
4392 if (FLOATP (Vframe_alpha_lower_limit))
4393 alpha_min = XFLOAT_DATA (Vframe_alpha_lower_limit);
4394 else if (FIXNUMP (Vframe_alpha_lower_limit))
4395 alpha_min = (XFIXNUM (Vframe_alpha_lower_limit)) / 100.0;
4396
4397 if (alpha > 1.0)
4398 alpha = 1.0;
4399 else if (alpha < alpha_min && alpha_min <= 1.0)
4400 alpha = alpha_min;
4401
4402#if 0
4403 /* If there is a parent from the window manager, put the property there
4404 also, to work around broken window managers that fail to do that.
4405 Do this unconditionally as this function is called on reparent when
4406 alpha has not changed on the frame. */
4407
4408 if (!FRAME_PARENT_FRAME (f))
4409 {
4410 Window parent = x_find_topmost_parent (f);
4411 if (parent != None)
4412 XChangeProperty (dpy, parent, dpyinfo->Xatom_net_wm_window_opacity,
4413 XA_CARDINAL, 32, PropModeReplace,
4414 (unsigned char *) &opac, 1);
4415 }
4416#endif
4417
4418 set_opacity_recursively (FRAME_GTK_OUTER_WIDGET (f), &alpha);
4419 /* without this, blending mode is strange on wayland. */
4420 gtk_widget_queue_resize_no_redraw (FRAME_GTK_OUTER_WIDGET (f));
4421}
4422
4423static void
4424frame_highlight (struct frame *f)
4425{
4426 /* We used to only do this if Vx_no_window_manager was non-nil, but
4427 the ICCCM (section 4.1.6) says that the window's border pixmap
4428 and border pixel are window attributes which are "private to the
4429 client", so we can always change it to whatever we want. */
4430 block_input ();
4431 /* I recently started to get errors in this XSetWindowBorder, depending on
4432 the window-manager in use, tho something more is at play since I've been
4433 using that same window-manager binary for ever. Let's not crash just
4434 because of this (bug#9310). */
4435#if 0
4436 x_catch_errors (FRAME_X_DISPLAY (f));
4437 XSetWindowBorder (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
4438 FRAME_X_OUTPUT(f)->border_pixel);
4439 x_uncatch_errors ();
4440#endif
4441 unblock_input ();
4442 gui_update_cursor (f, true);
4443 x_set_frame_alpha (f);
4444}
4445
4446static void
4447frame_unhighlight (struct frame *f)
4448{
4449 /* We used to only do this if Vx_no_window_manager was non-nil, but
4450 the ICCCM (section 4.1.6) says that the window's border pixmap
4451 and border pixel are window attributes which are "private to the
4452 client", so we can always change it to whatever we want. */
4453 block_input ();
4454 /* Same as above for XSetWindowBorder (bug#9310). */
4455#if 0
4456 x_catch_errors (FRAME_X_DISPLAY (f));
4457 XSetWindowBorderPixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
4458 FRAME_X_OUTPUT(f)->border_tile);
4459 x_uncatch_errors ();
4460#endif
4461 unblock_input ();
4462 gui_update_cursor (f, true);
4463 x_set_frame_alpha (f);
4464}
4465
4466
4467static void
4468pgtk_frame_rehighlight (struct pgtk_display_info *dpyinfo)
4469{
4470 struct frame *old_highlight = dpyinfo->highlight_frame;
4471
4472 if (dpyinfo->x_focus_frame)
4473 {
4474 dpyinfo->highlight_frame
4475 = ((FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame)))
4476 ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
4477 : dpyinfo->x_focus_frame);
4478 if (! FRAME_LIVE_P (dpyinfo->highlight_frame))
4479 {
4480 fset_focus_frame (dpyinfo->x_focus_frame, Qnil);
4481 dpyinfo->highlight_frame = dpyinfo->x_focus_frame;
4482 }
4483 }
4484 else
4485 dpyinfo->highlight_frame = 0;
4486
4487 if (dpyinfo->highlight_frame != old_highlight)
4488 {
4489 if (old_highlight)
4490 frame_unhighlight (old_highlight);
4491 if (dpyinfo->highlight_frame)
4492 frame_highlight (dpyinfo->highlight_frame);
4493 }
4494}
4495
4496/* The focus has changed, or we have redirected a frame's focus to
4497 another frame (this happens when a frame uses a surrogate
4498 mini-buffer frame). Shift the highlight as appropriate.
4499
4500 The FRAME argument doesn't necessarily have anything to do with which
4501 frame is being highlighted or un-highlighted; we only use it to find
4502 the appropriate X display info. */
4503
4504static void
4505XTframe_rehighlight (struct frame *frame)
4506{
4507 pgtk_frame_rehighlight (FRAME_DISPLAY_INFO (frame));
4508}
4509
4510/* The focus has changed. Update the frames as necessary to reflect
4511 the new situation. Note that we can't change the selected frame
4512 here, because the Lisp code we are interrupting might become confused.
4513 Each event gets marked with the frame in which it occurred, so the
4514 Lisp code can tell when the switch took place by examining the events. */
4515
4516static void
4517x_new_focus_frame (struct pgtk_display_info *dpyinfo, struct frame *frame)
4518{
4519 struct frame *old_focus = dpyinfo->x_focus_frame;
4520 /* doesn't work on wayland */
4521
4522 if (frame != dpyinfo->x_focus_frame)
4523 {
4524 /* Set this before calling other routines, so that they see
4525 the correct value of x_focus_frame. */
4526 dpyinfo->x_focus_frame = frame;
4527
4528 if (old_focus && old_focus->auto_lower)
4529 gdk_window_lower (gtk_widget_get_window (FRAME_GTK_OUTER_WIDGET (old_focus)));
4530
4531 if (dpyinfo->x_focus_frame && dpyinfo->x_focus_frame->auto_raise)
4532 gdk_window_raise (gtk_widget_get_window (FRAME_GTK_OUTER_WIDGET (dpyinfo->x_focus_frame)));
4533 }
4534
4535 pgtk_frame_rehighlight (dpyinfo);
4536}
4537
4354static struct terminal * 4538static struct terminal *
4355pgtk_create_terminal (struct pgtk_display_info *dpyinfo) 4539pgtk_create_terminal (struct pgtk_display_info *dpyinfo)
4356/* -------------------------------------------------------------------------- 4540/* --------------------------------------------------------------------------
@@ -4371,7 +4555,7 @@ pgtk_create_terminal (struct pgtk_display_info *dpyinfo)
4371 terminal->read_socket_hook = pgtk_read_socket; 4555 terminal->read_socket_hook = pgtk_read_socket;
4372 // terminal->frame_up_to_date_hook = pgtk_frame_up_to_date; 4556 // terminal->frame_up_to_date_hook = pgtk_frame_up_to_date;
4373 terminal->mouse_position_hook = pgtk_mouse_position; 4557 terminal->mouse_position_hook = pgtk_mouse_position;
4374 // terminal->frame_rehighlight_hook = pgtk_frame_rehighlight; 4558 terminal->frame_rehighlight_hook = XTframe_rehighlight;
4375 // terminal->frame_raise_lower_hook = pgtk_frame_raise_lower; 4559 // terminal->frame_raise_lower_hook = pgtk_frame_raise_lower;
4376 terminal->frame_visible_invisible_hook = pgtk_make_frame_visible_invisible; 4560 terminal->frame_visible_invisible_hook = pgtk_make_frame_visible_invisible;
4377 terminal->fullscreen_hook = pgtk_fullscreen_hook; 4561 terminal->fullscreen_hook = pgtk_fullscreen_hook;
@@ -5095,132 +5279,6 @@ static gboolean delete_event(GtkWidget *widget, GdkEvent *event, gpointer *user_
5095 return TRUE; 5279 return TRUE;
5096} 5280}
5097 5281
5098void
5099pgtk_focus_frame (struct frame *f, bool noactivate)
5100{
5101 struct pgtk_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
5102
5103 GtkWidget *wid = FRAME_GTK_OUTER_WIDGET(f);
5104
5105 if (dpyinfo->x_focus_frame != f)
5106 {
5107 block_input ();
5108 gtk_window_present (GTK_WINDOW (wid));
5109 unblock_input ();
5110 }
5111}
5112
5113
5114static void
5115frame_highlight (struct frame *f)
5116{
5117 /* We used to only do this if Vx_no_window_manager was non-nil, but
5118 the ICCCM (section 4.1.6) says that the window's border pixmap
5119 and border pixel are window attributes which are "private to the
5120 client", so we can always change it to whatever we want. */
5121 block_input ();
5122 /* I recently started to get errors in this XSetWindowBorder, depending on
5123 the window-manager in use, tho something more is at play since I've been
5124 using that same window-manager binary for ever. Let's not crash just
5125 because of this (bug#9310). */
5126#if 0
5127 x_catch_errors (FRAME_X_DISPLAY (f));
5128 XSetWindowBorder (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
5129 FRAME_X_OUTPUT(f)->border_pixel);
5130 x_uncatch_errors ();
5131#endif
5132 unblock_input ();
5133 gui_update_cursor (f, true);
5134#if 0
5135 x_set_frame_alpha (f);
5136#endif
5137}
5138
5139static void
5140frame_unhighlight (struct frame *f)
5141{
5142 /* We used to only do this if Vx_no_window_manager was non-nil, but
5143 the ICCCM (section 4.1.6) says that the window's border pixmap
5144 and border pixel are window attributes which are "private to the
5145 client", so we can always change it to whatever we want. */
5146 block_input ();
5147 /* Same as above for XSetWindowBorder (bug#9310). */
5148#if 0
5149 x_catch_errors (FRAME_X_DISPLAY (f));
5150 XSetWindowBorderPixmap (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
5151 FRAME_X_OUTPUT(f)->border_tile);
5152 x_uncatch_errors ();
5153#endif
5154 unblock_input ();
5155 gui_update_cursor (f, true);
5156#if 0
5157 x_set_frame_alpha (f);
5158#endif
5159}
5160
5161
5162static void
5163x_frame_rehighlight (struct pgtk_display_info *dpyinfo)
5164{
5165 struct frame *old_highlight = dpyinfo->highlight_frame;
5166
5167 if (dpyinfo->x_focus_frame)
5168 {
5169 dpyinfo->highlight_frame
5170 = ((FRAMEP (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame)))
5171 ? XFRAME (FRAME_FOCUS_FRAME (dpyinfo->x_focus_frame))
5172 : dpyinfo->x_focus_frame);
5173 if (! FRAME_LIVE_P (dpyinfo->highlight_frame))
5174 {
5175 fset_focus_frame (dpyinfo->x_focus_frame, Qnil);
5176 dpyinfo->highlight_frame = dpyinfo->x_focus_frame;
5177 }
5178 }
5179 else
5180 dpyinfo->highlight_frame = 0;
5181
5182 if (dpyinfo->highlight_frame != old_highlight)
5183 {
5184 if (old_highlight)
5185 frame_unhighlight (old_highlight);
5186 if (dpyinfo->highlight_frame)
5187 frame_highlight (dpyinfo->highlight_frame);
5188 }
5189}
5190
5191/* The focus has changed. Update the frames as necessary to reflect
5192 the new situation. Note that we can't change the selected frame
5193 here, because the Lisp code we are interrupting might become confused.
5194 Each event gets marked with the frame in which it occurred, so the
5195 Lisp code can tell when the switch took place by examining the events. */
5196
5197static void
5198x_new_focus_frame (struct pgtk_display_info *dpyinfo, struct frame *frame)
5199{
5200 struct frame *old_focus = dpyinfo->x_focus_frame;
5201
5202 if (frame != dpyinfo->x_focus_frame)
5203 {
5204 /* Set this before calling other routines, so that they see
5205 the correct value of x_focus_frame. */
5206 dpyinfo->x_focus_frame = frame;
5207
5208#if 0
5209 if (old_focus && old_focus->auto_lower)
5210 x_lower_frame (old_focus);
5211#endif
5212
5213#if 0
5214 if (dpyinfo->x_focus_frame && dpyinfo->x_focus_frame->auto_raise)
5215 dpyinfo->x_pending_autoraise_frame = dpyinfo->x_focus_frame;
5216 else
5217 dpyinfo->x_pending_autoraise_frame = NULL;
5218#endif
5219 }
5220
5221 x_frame_rehighlight (dpyinfo);
5222}
5223
5224/* The focus may have changed. Figure out if it is a real focus change, 5282/* The focus may have changed. Figure out if it is a real focus change,
5225 by checking both FocusIn/Out and Enter/LeaveNotify events. 5283 by checking both FocusIn/Out and Enter/LeaveNotify events.
5226 5284
@@ -5269,10 +5327,8 @@ x_focus_changed (gboolean is_enter, int state, struct pgtk_display_info *dpyinfo
5269 XSETFRAME (bufp->ie.frame_or_window, frame); 5327 XSETFRAME (bufp->ie.frame_or_window, frame);
5270 } 5328 }
5271 5329
5272#if 0
5273 if (frame->pointer_invisible) 5330 if (frame->pointer_invisible)
5274 XTtoggle_invisible_pointer (frame, false); 5331 XTtoggle_invisible_pointer (frame, false);
5275#endif
5276 } 5332 }
5277} 5333}
5278 5334
diff --git a/src/pgtkterm.h b/src/pgtkterm.h
index 4b585079b86..91990b203bd 100644
--- a/src/pgtkterm.h
+++ b/src/pgtkterm.h
@@ -579,5 +579,6 @@ extern void pgtk_set_scroll_bar_default_width (struct frame *f);
579extern void pgtk_set_scroll_bar_default_height (struct frame *f); 579extern void pgtk_set_scroll_bar_default_height (struct frame *f);
580extern Lisp_Object x_get_focus_frame (struct frame *frame); 580extern Lisp_Object x_get_focus_frame (struct frame *frame);
581 581
582extern void pgtk_frame_rehighlight (struct pgtk_display_info *dpyinfo);
582 583
583#endif /* HAVE_PGTK */ 584#endif /* HAVE_PGTK */