// IM-2016-01-21: [[ NativeLayer ]] Place the socket window relative to its // container, so only the visible area (clipped by any containing groups) // is displayed. void MCNativeLayerX11::doSetGeometry(const MCRectangle& p_rect) { m_rect = p_rect; updateContainerGeometry(); MCRectangle t_rect; t_rect = m_rect; t_rect.x -= m_intersect_rect.x; t_rect.y -= m_intersect_rect.y; // Move the overlay window first, to ensure events don't get stolen // Clear any minimum size parameters for the GTK widgets gtk_widget_set_size_request(GTK_WIDGET(m_socket), -1, -1); // Resize the socket gdk_window_move_resize(gtk_widget_get_window(GTK_WIDGET(m_socket)), t_rect.x, t_rect.y, t_rect.width, t_rect.height); // We need to set the requested minimum size in order to get in-process GTK // widgets to re-size automatically. Unfortunately, that is the only widget // category that this works for... others need to do it themselves. gtk_widget_set_size_request(GTK_WIDGET(m_socket), t_rect.width, t_rect.height); // Update the contained window too GdkWindow* t_remote; t_remote = gtk_socket_get_plug_window(m_socket); if (t_remote != NULL) gdk_window_move_resize(t_remote, t_rect.x, t_rect.y, t_rect.width, t_rect.height); }
/* If we are faking transparency with a window-relative background, force a * redraw of the icon. This should be called if the background changes or if * the child is shifted with respect to the background. */ void na_tray_child_force_redraw (NaTrayChild *child) { GtkWidget *widget = GTK_WIDGET (child); if (gtk_widget_get_mapped (widget) && child->parent_relative_bg) { #if 1 /* Sending an ExposeEvent might cause redraw problems if the * icon is expecting the server to clear-to-background before * the redraw. It should be ok for GtkStatusIcon or EggTrayIcon. */ Display *xdisplay = GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (widget)); XEvent xev; GdkWindow *plug_window; GtkAllocation allocation; plug_window = gtk_socket_get_plug_window (GTK_SOCKET (child)); gtk_widget_get_allocation (widget, &allocation); xev.xexpose.type = Expose; #if GTK_CHECK_VERSION (3, 0, 0) xev.xexpose.window = GDK_WINDOW_XID (plug_window); #else xev.xexpose.window = GDK_WINDOW_XWINDOW (plug_window); #endif xev.xexpose.x = 0; xev.xexpose.y = 0; xev.xexpose.width = allocation.width; xev.xexpose.height = allocation.height; xev.xexpose.count = 0; gdk_error_trap_push (); XSendEvent (GDK_DISPLAY_XDISPLAY (gtk_widget_get_display (widget)), xev.xexpose.window, False, ExposureMask, &xev); /* We have to sync to reliably catch errors from the XSendEvent(), * since that is asynchronous. */ XSync (xdisplay, False); #if GTK_CHECK_VERSION (3, 0, 0) gdk_error_trap_pop_ignored (); #else gdk_error_trap_pop (); #endif #else /* Hiding and showing is the safe way to do it, but can result in more * flickering. */ gdk_window_hide (widget->window); gdk_window_show (widget->window); #endif } }
/* FIXME: should we schedule the event or not? static gboolean schedule_send_client_event (gpointer data) { GdkEvent *event = (GdkEvent*) data; gdk_event_send_client_message (event, GDK_WINDOW_XID (event->client.window)); gdk_event_free (event); return FALSE; } */ static void on_size_alloc (AwnAppletProxy *proxy, GtkAllocation *alloc) { AwnAppletProxyPrivate *priv; GtkWidget *parent; GtkAllocation parent_alloc; GdkWindow *plug_win; g_return_if_fail (AWN_IS_APPLET_PROXY (proxy)); priv = proxy->priv; parent = gtk_widget_get_parent (GTK_WIDGET (proxy)); gtk_widget_get_allocation (parent, &parent_alloc); gint pos_x = alloc->x; gint pos_y = alloc->y; gint rel_x = pos_x - parent_alloc.x; gint rel_y = pos_y - parent_alloc.y; gint parent_w = parent_alloc.width; gint parent_h = parent_alloc.height; if (pos_x == priv->old_x && pos_y == priv->old_y && parent_w == priv->old_w && parent_h == priv->old_h) return; priv->old_x = pos_x; priv->old_y = pos_y; priv->old_w = parent_w; priv->old_h = parent_h; /* Only directly access the struct member if we have to. */ plug_win = gtk_socket_get_plug_window (GTK_SOCKET (proxy)); if (plug_win) { GdkAtom msg_type = gdk_atom_intern("_AWN_APPLET_POS_CHANGE", FALSE); GdkEvent *event = gdk_event_new (GDK_CLIENT_EVENT); event->client.window = g_object_ref (plug_win); event->client.data_format = 32; event->client.message_type = msg_type; // first two longs are our relative [x, y] event->client.data.l[0] = rel_x; event->client.data.l[1] = rel_y; // other two longs are our parent's [w, h] event->client.data.l[2] = parent_w; event->client.data.l[3] = parent_h; gdk_event_send_client_message (event, GDK_WINDOW_XID (plug_win)); gdk_event_free (event); /* g_idle_add (schedule_send_client_event, event); */ } }
static void cinnamon_tray_icon_constructed (GObject *object) { GdkWindow *icon_app_window; CinnamonTrayIcon *icon = CINNAMON_TRAY_ICON (object); CinnamonEmbeddedWindow *window; GdkDisplay *display; Window plug_xid; Atom _NET_WM_PID, type; int result, format; gulong nitems, bytes_after, *val = NULL; /* We do all this now rather than computing it on the fly later, * because Cinnamon may want to see their values from a * tray-icon-removed signal handler, at which point the plug has * already been removed from the socket. */ g_object_get (object, "window", &window, NULL); g_return_if_fail (window != NULL); icon->priv->socket = NA_TRAY_CHILD (gtk_bin_get_child (GTK_BIN (window))); g_object_unref (window); icon->priv->title = na_tray_child_get_title (icon->priv->socket); na_tray_child_get_wm_class (icon->priv->socket, NULL, &icon->priv->wm_class); icon_app_window = gtk_socket_get_plug_window (GTK_SOCKET (icon->priv->socket)); if (icon_app_window == NULL) { g_warning ("cinnamon tray: icon app window is gone"); return; } plug_xid = GDK_WINDOW_XID (icon_app_window); display = gtk_widget_get_display (GTK_WIDGET (icon->priv->socket)); gdk_error_trap_push (); _NET_WM_PID = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_PID"); result = XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), plug_xid, _NET_WM_PID, 0, G_MAXLONG, False, XA_CARDINAL, &type, &format, &nitems, &bytes_after, (guchar **)&val); if (!gdk_error_trap_pop () && result == Success && type == XA_CARDINAL && nitems == 1) icon->priv->pid = *val; if (val) XFree (val); }
GdkWindow * awn_ua_alignment_add_id (AwnUAAlignment *self,GdkNativeWindow native_window) { GdkWindow * plugwin; AwnUAAlignmentPrivate *priv; priv = AWN_UA_ALIGNMENT_GET_PRIVATE (self); gtk_socket_add_id (GTK_SOCKET(priv->socket), native_window); plugwin = gtk_socket_get_plug_window (GTK_SOCKET(priv->socket)); g_signal_connect (priv->socket,"plug-removed", G_CALLBACK(awn_ua_alignment_plug_removed),self); gtk_widget_realize (priv->socket); gtk_widget_show_all (priv->socket); return plugwin; }
static void na_tray_manager_handle_dock_request (NaTrayManager *manager, XClientMessageEvent *xevent) { Window icon_window = xevent->data.l[2]; GtkWidget *child; if (g_hash_table_lookup (manager->socket_table, GINT_TO_POINTER (icon_window))) { /* We already got this notification earlier, ignore this one */ return; } child = na_tray_child_new (manager->screen, icon_window); if (child == NULL) /* already gone or other error */ return; g_signal_emit (manager, manager_signals[TRAY_ICON_ADDED], 0, child); /* If the child wasn't attached, then destroy it */ if (!GTK_IS_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (child)))) { gtk_widget_destroy (child); return; } g_signal_connect (child, "plug_removed", G_CALLBACK (na_tray_manager_plug_removed), manager); gtk_socket_add_id (GTK_SOCKET (child), icon_window); if (!gtk_socket_get_plug_window (GTK_SOCKET (child))) { /* Embedding failed, we won't get a plug-removed signal */ /* This signal destroys the socket */ g_signal_emit (manager, manager_signals[TRAY_ICON_REMOVED], 0, child); return; } g_hash_table_insert (manager->socket_table, GINT_TO_POINTER (icon_window), child); gtk_widget_show (child); }
void MCNativeLayerX11::doAttach() { if (m_socket == NULL) { // Create a new GTK socket to deal with the XEMBED protocol GtkSocket *t_socket; t_socket = GTK_SOCKET(gtk_socket_new()); // Create a new GTK window to hold the socket MCRectangle t_rect; t_rect = m_object->getrect(); m_child_window = GTK_WINDOW(gtk_window_new(GTK_WINDOW_POPUP)); gtk_widget_set_parent_window(GTK_WIDGET(m_child_window), getStackGdkWindow()); gtk_widget_realize(GTK_WIDGET(m_child_window)); gdk_window_reparent(gtk_widget_get_window(GTK_WIDGET(m_child_window)), getStackGdkWindow(), t_rect.x, t_rect.y); // Add the socket to the window gtk_container_add(GTK_CONTAINER(m_child_window), GTK_WIDGET(t_socket)); // The socket needs to be realised before going any further or any // operations on it will fail. gtk_widget_realize(GTK_WIDGET(t_socket)); // Show the socket (we'll control visibility at the window level) gtk_widget_show(GTK_WIDGET(t_socket)); // Create an empty region to act as an input mask while in edit mode m_input_shape = gdk_region_new(); // Retain a reference to the socket m_socket = GTK_SOCKET(g_object_ref(G_OBJECT(t_socket))); } // Attach the X11 window to this socket if (gtk_socket_get_plug_window(m_socket) == NULL) gtk_socket_add_id(m_socket, m_widget_xid); //fprintf(stderr, "XID: %u\n", gtk_socket_get_id(m_socket)); // Act as if there were a re-layer to put the widget in the right place doRelayer(); doSetViewportGeometry(m_viewport_rect); doSetGeometry(m_rect); doSetVisible(ShouldShowLayer()); }
static void plug_added_cb(GtkWidget *socket, gpointer data) { // The plug window has been embedded, and gtk_socket_add_window() has added // a filter to the socket's plug_window, passing the socket as data for the // filter, so the socket must live as long as events may be received on the // plug window. // // https://git.gnome.org/browse/gtk+/tree/gtk/gtksocket.c?h=3.18.7#n1124 g_object_ref(socket); // When the socket is unrealized, perhaps during gtk_widget_destroy() from // ~nsPluginNativeWindowGtk, the plug is removed. The plug in the child // process then destroys its widget and window. When the browser process // receives the DestroyNotify event for the plug window, GDK releases its // reference to plugWindow. This is typically the last reference and so the // weak ref callback triggers release of the socket. GdkWindow* plugWindow = gtk_socket_get_plug_window(GTK_SOCKET(socket)); g_object_weak_ref(G_OBJECT(plugWindow), plug_window_finalize_cb, socket); }
static gint luaH_socket_index(lua_State *L, luapdf_token_t token) { widget_t *w = luaH_checkwidget(L, 1); switch(token) { LUAPDF_WIDGET_INDEX_COMMON /* push integer methods */ PI_CASE(ID, (int) gtk_socket_get_id(GTK_SOCKET(w->widget))) /* push boolean methods */ PB_CASE(PLUGGED, gtk_socket_get_plug_window(GTK_SOCKET(w->widget))!=NULL) default: break; } return 0; }
/** * shell_tray_icon_click: * @icon: a #ShellTrayIcon * @event: the #ClutterEvent triggering the fake click * * Fakes a press and release on @icon. @event must be a * %CLUTTER_BUTTON_RELEASE, %CLUTTER_KEY_PRESS or %CLUTTER_KEY_RELEASE event. * Its relevant details will be passed on to the icon, but its * coordinates will be ignored; the click is * always made on the center of @icon. */ void shell_tray_icon_click (ShellTrayIcon *icon, ClutterEvent *event) { XKeyEvent xkevent; XButtonEvent xbevent; XCrossingEvent xcevent; GdkWindow *remote_window; GdkScreen *screen; int x_root, y_root; Display *xdisplay; Window xwindow, xrootwindow; ClutterEventType event_type = clutter_event_type (event); g_return_if_fail (event_type == CLUTTER_BUTTON_RELEASE || event_type == CLUTTER_KEY_PRESS || event_type == CLUTTER_KEY_RELEASE); gdk_error_trap_push (); remote_window = gtk_socket_get_plug_window (GTK_SOCKET (icon->priv->socket)); xwindow = GDK_WINDOW_XID (remote_window); xdisplay = GDK_WINDOW_XDISPLAY (remote_window); screen = gdk_window_get_screen (remote_window); xrootwindow = GDK_WINDOW_XID (gdk_screen_get_root_window (screen)); gdk_window_get_origin (remote_window, &x_root, &y_root); /* First make the icon believe the pointer is inside it */ xcevent.type = EnterNotify; xcevent.window = xwindow; xcevent.root = xrootwindow; xcevent.subwindow = None; xcevent.time = clutter_event_get_time (event); xcevent.x = gdk_window_get_width (remote_window) / 2; xcevent.y = gdk_window_get_height (remote_window) / 2; xcevent.x_root = x_root + xcevent.x; xcevent.y_root = y_root + xcevent.y; xcevent.mode = NotifyNormal; xcevent.detail = NotifyNonlinear; xcevent.same_screen = True; XSendEvent (xdisplay, xwindow, False, 0, (XEvent *)&xcevent); /* Now do the click */ if (event_type == CLUTTER_BUTTON_RELEASE) { xbevent.window = xwindow; xbevent.root = xrootwindow; xbevent.subwindow = None; xbevent.time = xcevent.time; xbevent.x = xcevent.x; xbevent.y = xcevent.y; xbevent.x_root = xcevent.x_root; xbevent.y_root = xcevent.y_root; xbevent.state = clutter_event_get_state (event); xbevent.same_screen = True; xbevent.type = ButtonPress; xbevent.button = clutter_event_get_button (event); XSendEvent (xdisplay, xwindow, False, 0, (XEvent *)&xbevent); xbevent.type = ButtonRelease; XSendEvent (xdisplay, xwindow, False, 0, (XEvent *)&xbevent); } else { xkevent.window = xwindow; xkevent.root = xrootwindow; xkevent.subwindow = None; xkevent.time = xcevent.time; xkevent.x = xcevent.x; xkevent.y = xcevent.y; xkevent.x_root = xcevent.x_root; xkevent.y_root = xcevent.y_root; xkevent.state = clutter_event_get_state (event); xkevent.same_screen = True; xkevent.keycode = clutter_event_get_key_code (event); xkevent.type = KeyPress; XSendEvent (xdisplay, xwindow, False, 0, (XEvent *)&xkevent); if (event_type == CLUTTER_KEY_RELEASE) { /* If the application takes a grab on KeyPress, we don't * want to send it a KeyRelease. There's no good way of * knowing whether a tray icon will take a grab, so just * assume it does, and don't send the KeyRelease. That might * make the tracking for key events messed up if it doesn't take * a grab, but the tray icon won't get key focus in normal cases, * so let's hope this isn't too damaging... */ xkevent.type = KeyRelease; XSendEvent (xdisplay, xwindow, False, 0, (XEvent *)&xkevent); } } /* And move the pointer back out */ xcevent.type = LeaveNotify; XSendEvent (xdisplay, xwindow, False, 0, (XEvent *)&xcevent); gdk_error_trap_pop_ignored (); }
static gboolean gail_focus_watcher (GSignalInvocationHint *ihint, guint n_param_values, const GValue *param_values, gpointer data) { GObject *object; GtkWidget *widget; GdkEvent *event; object = g_value_get_object (param_values + 0); g_return_val_if_fail (GTK_IS_WIDGET(object), FALSE); event = g_value_get_boxed (param_values + 1); widget = GTK_WIDGET (object); if (event->type == GDK_FOCUS_CHANGE) { if (event->focus_change.in) { if (GTK_IS_WINDOW (widget)) { GtkWidget *focus_widget; GtkWindow *window; GtkWindowType type; window = GTK_WINDOW (widget); focus_widget = gtk_window_get_focus (window); g_object_get (window, "type", &type, NULL); if (focus_widget) { /* * If we already have a potential focus widget set this * windows's focus widget to focus_before_menu so that * it will be reported when menu item is unset. */ if (next_focus_widget) { if (GTK_IS_MENU_ITEM (next_focus_widget) && !focus_before_menu) { void *vp_focus_before_menu = &focus_before_menu; focus_before_menu = focus_widget; g_object_add_weak_pointer (G_OBJECT (focus_before_menu), vp_focus_before_menu); } return TRUE; } widget = focus_widget; } else if (type == GTK_WINDOW_POPUP) { if (GTK_IS_BIN (widget)) { GtkWidget *child = gtk_bin_get_child (GTK_BIN (widget)); if (GTK_IS_WIDGET (child) && gtk_widget_has_grab (child)) { if (GTK_IS_MENU_SHELL (child)) { if (gtk_menu_shell_get_selected_item (GTK_MENU_SHELL (child))) { /* * We have a menu which has a menu item selected * so we do not report focus on the menu. */ return TRUE; } } widget = child; } } else /* popup window has no children; this edge case occurs in some custom code (OOo for instance) */ { return TRUE; } } else /* Widget is a non-popup toplevel with no focus children; don't emit for this case either, as it's useless */ { return TRUE; } } } else { if (next_focus_widget) { GtkWidget *toplevel; toplevel = gtk_widget_get_toplevel (next_focus_widget); if (toplevel == widget) next_focus_widget = NULL; } /* focus out */ widget = NULL; } } else { if (event->type == GDK_MOTION_NOTIFY && gtk_widget_has_focus (widget)) { if (widget == _focus_widget) { return TRUE; } } else { return TRUE; } } #ifdef GDK_WINDOWING_X11 /* * If the focus widget is a GtkSocket without a plug * then ignore the focus notification as the embedded * plug will report a focus notification. */ if (GTK_IS_SOCKET (widget) && gtk_socket_get_plug_window (GTK_SOCKET (widget)) != NULL) return TRUE; #endif /* * The widget may not yet be visible on the screen so we wait until it is. */ gail_focus_notify_when_idle (widget); return TRUE; }
/** * cinnamon_tray_icon_click: * @icon: a #CinnamonTrayIcon * @event: the #ClutterEvent triggering the fake click * * Fakes a press and release on @icon. @event must be a * %CLUTTER_BUTTON_RELEASE event. Its relevant details will be passed * on to the icon, but its coordinates will be ignored; the click is * always made on the center of @icon. */ void cinnamon_tray_icon_click (CinnamonTrayIcon *icon, ClutterEvent *event) { XButtonEvent xbevent; XCrossingEvent xcevent; GdkWindow *remote_window; GdkScreen *screen; int x_root, y_root; Display *xdisplay; Window xwindow, xrootwindow; g_return_if_fail (clutter_event_type (event) == CLUTTER_BUTTON_RELEASE); gdk_error_trap_push (); remote_window = gtk_socket_get_plug_window (GTK_SOCKET (icon->priv->socket)); if (remote_window == NULL) { g_warning ("cinnamon tray: plug window is gone"); gdk_error_trap_pop_ignored (); return; } xwindow = GDK_WINDOW_XID (remote_window); xdisplay = GDK_WINDOW_XDISPLAY (remote_window); screen = gdk_window_get_screen (remote_window); xrootwindow = GDK_WINDOW_XID (gdk_screen_get_root_window (screen)); gdk_window_get_origin (remote_window, &x_root, &y_root); /* First make the icon believe the pointer is inside it */ xcevent.type = EnterNotify; xcevent.window = xwindow; xcevent.root = xrootwindow; xcevent.subwindow = None; xcevent.time = clutter_event_get_time (event); xcevent.x = gdk_window_get_width (remote_window) / 2; xcevent.y = gdk_window_get_height (remote_window) / 2; xcevent.x_root = x_root + xcevent.x; xcevent.y_root = y_root + xcevent.y; xcevent.mode = NotifyNormal; xcevent.detail = NotifyNonlinear; xcevent.same_screen = True; XSendEvent (xdisplay, xwindow, False, 0, (XEvent *)&xcevent); /* Now do the click */ xbevent.type = ButtonPress; xbevent.window = xwindow; xbevent.root = xrootwindow; xbevent.subwindow = None; xbevent.time = xcevent.time; xbevent.x = xcevent.x; xbevent.y = xcevent.y; xbevent.x_root = xcevent.x_root; xbevent.y_root = xcevent.y_root; xbevent.state = clutter_event_get_state (event); xbevent.button = clutter_event_get_button (event); xbevent.same_screen = True; XSendEvent (xdisplay, xwindow, False, 0, (XEvent *)&xbevent); xbevent.type = ButtonRelease; XSendEvent (xdisplay, xwindow, False, 0, (XEvent *)&xbevent); /* And move the pointer back out */ xcevent.type = LeaveNotify; XSendEvent (xdisplay, xwindow, False, 0, (XEvent *)&xcevent); gdk_error_trap_pop_ignored (); }