diff --git a/12to11-test.xml b/12to11-test.xml index 99fe3fd..5089fee 100644 --- a/12to11-test.xml +++ b/12to11-test.xml @@ -159,6 +159,17 @@ + + + + The activated is sent when the xdg_activation protocol causes + the surface associated with the role to be activated. Its + parameters constitute the timestamp at which the activation + occurred. + + + + diff --git a/12to11.c b/12to11.c index 8b275fe..3a40370 100644 --- a/12to11.c +++ b/12to11.c @@ -248,6 +248,7 @@ XLMain (int argc, char **argv) XLInitKeyboardShortcutsInhibit (); XLInitIdleInhibit (); XLInitPointerGestures (); + XLInitXdgActivation (); XLInitTest (); /* This has to come after the rest of the initialization. */ diff --git a/Imakefile b/Imakefile index 0f7a229..54456cc 100644 --- a/Imakefile +++ b/Imakefile @@ -18,8 +18,8 @@ MakeSubdirs($(SUBDIRS)) DependSubdirs($(SUBDIRS)) #endif - SRCS = 12to11.c run.c alloc.c fns.c output.c compositor.c surface.c region.c shm.c atoms.c subcompositor.c positioner.c xdg_wm.c xdg_surface.c xdg_toplevel.c frame_clock.c xerror.c ewmh.c timer.c subsurface.c seat.c data_device.c xdg_popup.c dmabuf.c buffer.c select.c xdata.c xsettings.c dnd.c icon_surface.c primary_selection.c renderer.c picture_renderer.c explicit_synchronization.c transform.c wp_viewporter.c decoration.c text_input.c single_pixel_buffer.c drm_lease.c pointer_constraints.c time.c relative_pointer.c keyboard_shortcuts_inhibit.c idle_inhibit.c process.c fence_ring.c pointer_gestures.c test.c buffer_release.c - OBJS = 12to11.o run.o alloc.o fns.o output.o compositor.o surface.o region.o shm.o atoms.o subcompositor.o positioner.o xdg_wm.o xdg_surface.o xdg_toplevel.o frame_clock.o xerror.o ewmh.o timer.o subsurface.o seat.o data_device.o xdg_popup.o dmabuf.o buffer.o select.o xdata.o xsettings.o dnd.o icon_surface.o primary_selection.o renderer.o picture_renderer.o explicit_synchronization.o transform.o wp_viewporter.o decoration.o text_input.o single_pixel_buffer.o drm_lease.o pointer_constraints.o time.o relative_pointer.o keyboard_shortcuts_inhibit.o idle_inhibit.o process.o fence_ring.o pointer_gestures.o test.o buffer_release.o + SRCS = 12to11.c run.c alloc.c fns.c output.c compositor.c surface.c region.c shm.c atoms.c subcompositor.c positioner.c xdg_wm.c xdg_surface.c xdg_toplevel.c frame_clock.c xerror.c ewmh.c timer.c subsurface.c seat.c data_device.c xdg_popup.c dmabuf.c buffer.c select.c xdata.c xsettings.c dnd.c icon_surface.c primary_selection.c renderer.c picture_renderer.c explicit_synchronization.c transform.c wp_viewporter.c decoration.c text_input.c single_pixel_buffer.c drm_lease.c pointer_constraints.c time.c relative_pointer.c keyboard_shortcuts_inhibit.c idle_inhibit.c process.c fence_ring.c pointer_gestures.c test.c buffer_release.c xdg_activation.c + OBJS = 12to11.o run.o alloc.o fns.o output.o compositor.o surface.o region.o shm.o atoms.o subcompositor.o positioner.o xdg_wm.o xdg_surface.o xdg_toplevel.o frame_clock.o xerror.o ewmh.o timer.o subsurface.o seat.o data_device.o xdg_popup.o dmabuf.o buffer.o select.o xdata.o xsettings.o dnd.o icon_surface.o primary_selection.o renderer.o picture_renderer.o explicit_synchronization.o transform.o wp_viewporter.o decoration.o text_input.o single_pixel_buffer.o drm_lease.o pointer_constraints.o time.o relative_pointer.o keyboard_shortcuts_inhibit.o idle_inhibit.o process.o fence_ring.o pointer_gestures.o test.o buffer_release.o xdg_activation.o GENHEADERS = transfer_atoms.h drm_modifiers.h HEADER = $(GENHEADERS) compositor.h @@ -105,6 +105,7 @@ ScannerTarget(keyboard-shortcuts-inhibit-unstable-v1) ScannerTarget(idle-inhibit-unstable-v1) ScannerTarget(pointer-gestures-unstable-v1) ScannerTarget(12to11-test) +ScannerTarget(xdg-activation-v1) /* Make seat.o depend on test_seat.c, as it includes that. Both files are rather special. */ diff --git a/atoms.c b/atoms.c index ea9028a..228e8f1 100644 --- a/atoms.c +++ b/atoms.c @@ -112,6 +112,7 @@ static const char *names[] = "_NET_WM_PID", "_NET_WM_PING", "libinput Scrolling Pixel Distance", + "_NET_ACTIVE_WINDOW", /* These are automatically generated from mime.txt. */ DirectTransferAtomNames @@ -134,7 +135,8 @@ Atom _NET_WM_OPAQUE_REGION, _XL_BUFFER_RELEASE, _NET_WM_SYNC_REQUEST_COUNTER, XdndEnter, XdndPosition, XdndStatus, XdndLeave, XdndDrop, XdndFinished, _NET_WM_FRAME_TIMINGS, _NET_WM_BYPASS_COMPOSITOR, WM_STATE, _NET_WM_WINDOW_TYPE, _NET_WM_WINDOW_TYPE_MENU, _NET_WM_WINDOW_TYPE_DND, - CONNECTOR_ID, _NET_WM_PID, _NET_WM_PING, libinput_Scrolling_Pixel_Distance; + CONNECTOR_ID, _NET_WM_PID, _NET_WM_PING, libinput_Scrolling_Pixel_Distance, + _NET_ACTIVE_WINDOW; XrmQuark resource_quark, app_quark, QString; @@ -292,9 +294,10 @@ XLInitAtoms (void) _NET_WM_PID = atoms[62]; _NET_WM_PING = atoms[63]; libinput_Scrolling_Pixel_Distance = atoms[64]; + _NET_ACTIVE_WINDOW = atoms[65]; /* This is automatically generated. */ - DirectTransferAtomInit (atoms, 65); + DirectTransferAtomInit (atoms, 66); /* Now, initialize quarks. */ resource_quark = XrmPermStringToQuark (compositor.resource_name); diff --git a/compositor.h b/compositor.h index bc4340f..7e742ab 100644 --- a/compositor.h +++ b/compositor.h @@ -1145,6 +1145,7 @@ struct _RoleFuncs void (*select_extra_events) (Surface *, Role *, unsigned long); void (*note_focus) (Surface *, Role *, FocusMode); void (*outputs_changed) (Surface *, Role *); + void (*activate) (Surface *, Role *, int, Timestamp); }; struct _Role @@ -1238,7 +1239,8 @@ extern Atom _NET_WM_OPAQUE_REGION, _XL_BUFFER_RELEASE, XdndProxy, XdndEnter, XdndPosition, XdndStatus, XdndLeave, XdndDrop, XdndFinished, _NET_WM_FRAME_TIMINGS, _NET_WM_BYPASS_COMPOSITOR, WM_STATE, _NET_WM_WINDOW_TYPE, _NET_WM_WINDOW_TYPE_MENU, _NET_WM_WINDOW_TYPE_DND, - CONNECTOR_ID, _NET_WM_PID, _NET_WM_PING, libinput_Scrolling_Pixel_Distance; + CONNECTOR_ID, _NET_WM_PID, _NET_WM_PING, libinput_Scrolling_Pixel_Distance, + _NET_ACTIVE_WINDOW; extern XrmQuark resource_quark, app_quark, QString; @@ -1340,6 +1342,7 @@ struct _XdgRoleImplementationFuncs void (*note_focus) (Role *, XdgRoleImplementation *, FocusMode); void (*outputs_changed) (Role *, XdgRoleImplementation *); void (*after_commit) (Role *, Surface *, XdgRoleImplementation *); + void (*activate) (Role *, XdgRoleImplementation *, int, Time); }; struct _XdgRoleImplementation @@ -1616,6 +1619,7 @@ extern PinchGesture *XLSeatGetPinchGesture (Seat *, struct wl_resource *); extern void XLSeatDestroySwipeGesture (SwipeGesture *); extern void XLSeatDestroyPinchGesture (PinchGesture *); extern KeyCode XLKeysymToKeycode (KeySym, XEvent *); +extern Bool XLSeatCheckActivationSerial (Seat *, uint32_t); extern Cursor InitDefaultCursor (void); @@ -1857,6 +1861,10 @@ extern void ReleaseBufferWithHelper (BufferReleaseHelper *, ExtBuffer *, extern void XLGetTestSeat (struct wl_client *, struct wl_resource *, uint32_t); +/* Defined in xdg_activation.c. */ + +extern void XLInitXdgActivation (void); + /* Utility functions that don't belong in a specific file. */ #define ArrayElements(arr) (sizeof (arr) / sizeof (arr)[0]) diff --git a/seat.c b/seat.c index a5f281b..05673eb 100644 --- a/seat.c +++ b/seat.c @@ -6387,6 +6387,20 @@ XLKeysymToKeycode (KeySym keysym, XEvent *event) return 0; } +Bool +XLSeatCheckActivationSerial (Seat *seat, uint32_t serial) +{ + /* Check if the specified serial can be used to activate surfaces on + behalf of seat. */ + + return ((seat->last_button_press_serial + && serial >= seat->last_button_press_serial) + || (seat->last_button_serial + && serial >= seat->last_button_press_serial) + || (seat->last_keyboard_serial + && serial >= seat->last_keyboard_serial)); +} + /* This is a particularly ugly hack, but there is no other way to expose all the internals needed by test_seat.c. */ diff --git a/test.c b/test.c index c27f669..c80af8b 100644 --- a/test.c +++ b/test.c @@ -336,6 +336,20 @@ GetWindow (Surface *surface, Role *role) return test->window; } +static void +Activate (Surface *surface, Role *role, int deviceid, + Timestamp timestamp) +{ + TestSurface *test; + + test = TestSurfaceFromRole (role); + + if (test->role.resource) + test_surface_send_activated (test->role.resource, + timestamp.months, + timestamp.milliseconds); +} + static const struct test_surface_interface test_surface_impl = { .destroy = Destroy, @@ -489,6 +503,7 @@ GetTestSurface (struct wl_client *client, struct wl_resource *resource, test->role.funcs.release_buffer = ReleaseBuffer; test->role.funcs.subsurface_update = SubsurfaceUpdate; test->role.funcs.get_window = GetWindow; + test->role.funcs.activate = Activate; /* Add the resource implementation. */ wl_resource_set_implementation (test->role.resource, &test_surface_impl, diff --git a/tests/Imakefile b/tests/Imakefile index fb4ad0d..7d2d81d 100644 --- a/tests/Imakefile +++ b/tests/Imakefile @@ -26,6 +26,7 @@ name.c: $(12TO11ROOT)/name.xml name.h @@\ ScannerTarget(12to11-test) ScannerTarget(viewporter) ScannerTarget(linux-dmabuf-unstable-v1) +ScannerTarget(xdg-activation-v1) /* Not actually a test. */ SRCS1 = $(COMMONSRCS) imgview.c @@ -52,7 +53,9 @@ ScannerTarget(linux-dmabuf-unstable-v1) OBJS11 = select_helper.o SRCS12 = select_helper_multiple.c OBJS12 = select_helper_multiple.o - PROGRAMS = imgview simple_test damage_test transform_test viewporter_test subsurface_test scale_test seat_test dmabuf_test select_test select_helper select_helper_multiple + SRCS13 = $(COMMONSRCS) xdg_activation_test.c + OBJS13 = $(COMMONSRCS) xdg_activation_test.o + PROGRAMS = imgview simple_test damage_test transform_test viewporter_test subsurface_test scale_test seat_test dmabuf_test select_test select_helper select_helper_multiple xdg_activation_test /* Make all objects depend on HEADER. */ $(OBJS1): $(HEADER) @@ -72,10 +75,12 @@ NormalProgramTarget(dmabuf_test,$(OBJS9),NullParameter,$(LOCAL_LIBRARIES) $(GBM) NormalProgramTarget(select_test,$(OBJS10),NullParameter,$(LOCAL_LIBRARIES) ThreadsLibraries,NullParameter); NormalProgramTarget(select_helper,$(OBJS11),NullParameter,$(XLIB),NullParameter); NormalProgramTarget(select_helper_multiple,$(OBJS12),NullParameter,$(XLIB),NullParameter); +NormalProgramTarget(xdg_activation_test,$(OBJS13),NullParameter,$(LOCAL_LIBRARIES),NullParameter) DependTarget3($(SRCS1),$(SRCS2),$(SRCS3)) DependTarget3($(SRCS4),$(SRCS5),$(SRCS6)) DependTarget3($(SRCS7),$(SRCS8),$(SRCS9)) DependTarget3($(SRCS10),$(SRCS11),$(SRCS12)) +DependTarget3($(SRCS13),NullParameter,NullParameter) all:: $(PROGRAMS) diff --git a/tests/run_tests.sh b/tests/run_tests.sh index bdd4572..d171c46 100755 --- a/tests/run_tests.sh +++ b/tests/run_tests.sh @@ -22,6 +22,7 @@ pushd "$(dirname $0)" declare -a standard_tests=( simple_test damage_test transform_test viewporter_test subsurface_test scale_test seat_test dmabuf_test + xdg_activation_test ) make -C . "${standard_tests[@]}" diff --git a/tests/svnignore.txt b/tests/svnignore.txt index 246cf29..8fe643c 100644 --- a/tests/svnignore.txt +++ b/tests/svnignore.txt @@ -12,6 +12,7 @@ dmabuf_test select_test select_helper select_helper_multiple +xdg_activation_test imgview reject.dump Makefile diff --git a/xdg_surface.c b/xdg_surface.c index ca22c22..6f8a205 100644 --- a/xdg_surface.c +++ b/xdg_surface.c @@ -1392,6 +1392,20 @@ OutputsChanged (Surface *surface, Role *role) xdg_role->impl->funcs.outputs_changed (role, xdg_role->impl); } +static void +Activate (Surface *surface, Role *role, int deviceid, + Timestamp timestamp) +{ + XdgRole *xdg_role; + + xdg_role = XdgRoleFromRole (role); + + if (xdg_role->impl && xdg_role->impl->funcs.activate) + xdg_role->impl->funcs.activate (role, xdg_role->impl, + deviceid, + timestamp.milliseconds); +} + void XLGetXdgSurface (struct wl_client *client, struct wl_resource *resource, uint32_t id, struct wl_resource *surface_resource) @@ -1464,6 +1478,7 @@ XLGetXdgSurface (struct wl_client *client, struct wl_resource *resource, role->role.funcs.select_extra_events = SelectExtraEvents; role->role.funcs.note_focus = NoteFocus; role->role.funcs.outputs_changed = OutputsChanged; + role->role.funcs.activate = Activate; attrs.colormap = compositor.colormap; attrs.border_pixel = border_pixel; diff --git a/xdg_toplevel.c b/xdg_toplevel.c index fc9a1a1..234c992 100644 --- a/xdg_toplevel.c +++ b/xdg_toplevel.c @@ -31,6 +31,8 @@ along with 12to11. If not, see . */ #include "xdg-shell.h" #include "xdg-decoration-unstable-v1.h" +#include + #define ToplevelFromRoleImpl(impl) ((XdgToplevel *) (impl)) typedef struct _XdgToplevel XdgToplevel; @@ -2253,6 +2255,49 @@ OutputsChanged (Role *role, XdgRoleImplementation *impl) } } +static void +Activate (Role *role, XdgRoleImplementation *impl, int deviceid, + Time time) +{ + XEvent message; + XdgToplevel *toplevel; + Window window; + + toplevel = ToplevelFromRoleImpl (impl); + window = XLWindowFromXdgRole (toplevel->role); + + if (XLWmSupportsHint (_NET_ACTIVE_WINDOW)) + { + /* Use a _NET_ACTIVE_WINDOW request. */ + message.xclient.type = ClientMessage; + message.xclient.window = window; + message.xclient.message_type = _NET_ACTIVE_WINDOW; + message.xclient.format = 32; + message.xclient.data.l[0] = 1; + message.xclient.data.l[1] = time; + message.xclient.data.l[2] = None; + message.xclient.data.l[3] = 0; + message.xclient.data.l[4] = 0; + + fprintf (stderr, "activate at: %d\n", (int) time); + + XSendEvent (compositor.display, + DefaultRootWindow (compositor.display), + False, (SubstructureRedirectMask + | SubstructureNotifyMask), + &message); + } + else + { + /* Catch errors as we cannot be sure that the window is viewable + or that the device still exists. */ + CatchXErrors (); + XISetFocus (compositor.display, deviceid, + window, time); + UncatchXErrors (NULL); + } +} + static const struct xdg_toplevel_interface xdg_toplevel_impl = { .destroy = Destroy, @@ -2319,6 +2364,7 @@ XLGetXdgToplevel (struct wl_client *client, struct wl_resource *resource, toplevel->impl.funcs.is_window_mapped = IsWindowMapped; toplevel->impl.funcs.outputs_changed = OutputsChanged; toplevel->impl.funcs.after_commit = AfterCommit; + toplevel->impl.funcs.activate = Activate; if (!XLWmSupportsHint (_NET_WM_STATE_FOCUSED)) /* If _NET_WM_STATE_FOCUSED is unsupported, fall back to utilizing