static bool wxQueryWMspecSupport(Display* WXUNUSED(display), Window WXUNUSED(rootWnd), Atom (feature)) { GdkAtom gatom = gdk_x11_xatom_to_atom(feature); return gdk_x11_screen_supports_net_wm_hint(gdk_screen_get_default(), gatom); }
static guint32 get_netwm_cardinal_property (GdkScreen *screen, const gchar *name) { GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen); GdkAtom atom; guint32 prop = 0; Atom type; gint format; gulong nitems; gulong bytes_after; guchar *data; atom = gdk_atom_intern_static_string (name); if (!gdk_x11_screen_supports_net_wm_hint (screen, atom)) return 0; XGetWindowProperty (x11_screen->xdisplay, x11_screen->xroot_window, gdk_x11_get_xatom_by_name_for_display (GDK_SCREEN_DISPLAY (screen), name), 0, G_MAXLONG, False, XA_CARDINAL, &type, &format, &nitems, &bytes_after, &data); if (type == XA_CARDINAL) { prop = *(gulong *)data; XFree (data); } return prop; }
/* Handler for "clicked" signal on main widget. */ static gboolean wincmd_button_clicked(GtkWidget * widget, GdkEventButton * event, LXPanel * panel) { WinCmdPlugin * wc = lxpanel_plugin_get_data(widget); /* Left-click to iconify. */ if (event->button == 1) { GdkScreen* screen = gtk_widget_get_screen(widget); static GdkAtom atom = 0; if( G_UNLIKELY(0 == atom) ) atom = gdk_atom_intern("_NET_SHOWING_DESKTOP", FALSE); /* If window manager supports _NET_SHOWING_DESKTOP, use it. * Otherwise, fall back to iconifying windows individually. */ if (gdk_x11_screen_supports_net_wm_hint(screen, atom)) { int showing_desktop = ((( ! wc->toggle_preference) || ( ! wc->toggle_state)) ? 1 : 0); Xclimsg(DefaultRootWindow(GDK_DISPLAY_XDISPLAY(gdk_display_get_default())), a_NET_SHOWING_DESKTOP, showing_desktop, 0, 0, 0, 0); wincmd_adjust_toggle_state(wc); } else wincmd_execute(wc, WC_ICONIFY); } /* Middle-click to shade. */ else if (event->button == 2) wincmd_execute(wc, WC_SHADE); return TRUE; }
static void button_toggled_callback(GtkWidget* button, ShowDesktopData* sdd) { if (!gdk_x11_screen_supports_net_wm_hint(gtk_widget_get_screen(button), gdk_atom_intern("_NET_SHOWING_DESKTOP", FALSE))) { static GtkWidget* dialog = NULL; if (dialog && gtk_widget_get_screen(dialog) != gtk_widget_get_screen(button)) gtk_widget_destroy (dialog); if (dialog) { gtk_window_present(GTK_WINDOW(dialog)); return; } dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, _("Your window manager does not support the show desktop button, or you are not running a window manager.")); g_object_add_weak_pointer(G_OBJECT(dialog), (gpointer) &dialog); g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(gtk_widget_destroy), NULL); gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE); gtk_window_set_screen(GTK_WINDOW(dialog), gtk_widget_get_screen(button)); gtk_widget_show(dialog); return; } if (sdd->matewnck_screen != NULL) matewnck_screen_toggle_showing_desktop(sdd->matewnck_screen, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button))); update_button_display (sdd); }
static GList * gdk_x11_screen_get_window_stack (GdkScreen *screen) { GdkX11Screen *x11_screen; GList *ret = NULL; Atom type_return; gint format_return; gulong nitems_return; gulong bytes_after_return; guchar *data = NULL; g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL); if (!gdk_x11_screen_supports_net_wm_hint (screen, gdk_atom_intern_static_string ("_NET_CLIENT_LIST_STACKING"))) return NULL; x11_screen = GDK_X11_SCREEN (screen); if (XGetWindowProperty (x11_screen->xdisplay, x11_screen->xroot_window, gdk_x11_get_xatom_by_name_for_display (x11_screen->display, "_NET_CLIENT_LIST_STACKING"), 0, G_MAXLONG, False, XA_WINDOW, &type_return, &format_return, &nitems_return, &bytes_after_return, &data) == Success) { if ((type_return == XA_WINDOW) && (format_return == 32) && (data) && (nitems_return > 0)) { gulong *stack = (gulong *) data; GdkWindow *win; int i; for (i = 0; i < nitems_return; i++) { win = gdk_x11_window_foreign_new_for_display (x11_screen->display, (Window)stack[i]); if (win != NULL) ret = g_list_append (ret, win); } } } if (data) XFree (data); return ret; }
/* This function will make sure that tilda window becomes active (gains * the focus) when it is called. * * This has to be the worst possible way of making this work, but it was the * only way to get metacity to play nicely. All the other WM's are so nice, * why oh why does metacity hate us so? */ void tilda_window_set_active (tilda_window *tw) { DEBUG_FUNCTION ("tilda_window_set_active"); DEBUG_ASSERT (tw != NULL); Display *x11_display = GDK_WINDOW_XDISPLAY (gtk_widget_get_window (tw->window) ); Window x11_window = GDK_WINDOW_XID (gtk_widget_get_window (tw->window) ); Window x11_root_window = GDK_WINDOW_XID ( gtk_widget_get_root_window (tw->window) ); GdkScreen *screen = gtk_widget_get_screen (tw->window); XEvent event; long mask = SubstructureRedirectMask | SubstructureNotifyMask; gtk_window_move (GTK_WINDOW(tw->window), config_getint ("x_pos"), config_getint ("y_pos")); if (gdk_x11_screen_supports_net_wm_hint (screen, gdk_atom_intern_static_string ("_NET_ACTIVE_WINDOW"))) { guint32 timestamp = gtk_get_current_event_time (); if (timestamp == 0) { timestamp = gdk_x11_get_server_time(gdk_screen_get_root_window (screen)); } event.xclient.type = ClientMessage; event.xclient.serial = 0; event.xclient.send_event = True; event.xclient.display = x11_display; event.xclient.window = x11_window; event.xclient.message_type = gdk_x11_get_xatom_by_name ("_NET_ACTIVE_WINDOW"); event.xclient.format = 32; event.xclient.data.l[0] = 2; /* pager */ event.xclient.data.l[1] = timestamp; /* timestamp */ event.xclient.data.l[2] = 0; event.xclient.data.l[3] = 0; event.xclient.data.l[4] = 0; XSendEvent (x11_display, x11_root_window, False, mask, &event); } else { /* The WM doesn't support the EWMH standards. We'll print a warning and * try this, though it probably won't work... */ g_printerr (_("WARNING: Window manager (%s) does not support EWMH hints\n"), gdk_x11_screen_get_window_manager_name (screen)); XRaiseWindow (x11_display, x11_window); } }
static GdkWindow * gdk_x11_screen_get_active_window (GdkScreen *screen) { GdkX11Screen *x11_screen; GdkWindow *ret = NULL; Atom type_return; gint format_return; gulong nitems_return; gulong bytes_after_return; guchar *data = NULL; g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL); if (!gdk_x11_screen_supports_net_wm_hint (screen, gdk_atom_intern_static_string ("_NET_ACTIVE_WINDOW"))) return NULL; x11_screen = GDK_X11_SCREEN (screen); if (XGetWindowProperty (x11_screen->xdisplay, x11_screen->xroot_window, gdk_x11_get_xatom_by_name_for_display (x11_screen->display, "_NET_ACTIVE_WINDOW"), 0, 1, False, XA_WINDOW, &type_return, &format_return, &nitems_return, &bytes_after_return, &data) == Success) { if ((type_return == XA_WINDOW) && (format_return == 32) && (data)) { Window window = *(Window *) data; if (window != None) { ret = gdk_x11_window_foreign_new_for_display (x11_screen->display, window); } } } if (data) XFree (data); return ret; }
void gdk_x11_window_force_focus (GdkWindow *window, guint32 timestamp) { GdkDisplay *display; g_return_if_fail (GDK_IS_WINDOW (window)); display = GDK_WINDOW_DISPLAY (window); if (GTK_CHECK_VERSION(3,0,0) && !GDK_IS_X11_DISPLAY (display)) return; if (gdk_x11_screen_supports_net_wm_hint (gdk_window_get_screen (window), gdk_atom_intern_static_string ("_NET_ACTIVE_WINDOW"))) { if (!timestamp) { GTimeVal t; g_get_current_time (&t); timestamp = t.tv_sec; } XClientMessageEvent xclient; memset (&xclient, 0, sizeof (xclient)); xclient.type = ClientMessage; xclient.window = GDK_WINDOW_XID (window); xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "_NET_ACTIVE_WINDOW"); xclient.format = 32; xclient.data.l[0] = 2; /* requestor type; we're a tool */ xclient.data.l[1] = timestamp; xclient.data.l[2] = None; /* currently active window */ xclient.data.l[3] = 0; xclient.data.l[4] = 0; XSendEvent (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XROOTWIN (window), False, SubstructureRedirectMask | SubstructureNotifyMask, (XEvent *)&xclient); } }
static int get_current_desktop (GdkScreen *screen) { Display *display; Window win; Atom current_desktop, type; int format; unsigned long n_items, bytes_after; unsigned char *data_return = NULL; int workspace = 0; if (!gdk_x11_screen_supports_net_wm_hint (screen, gdk_atom_intern_static_string ("_NET_CURRENT_DESKTOP"))) return workspace; display = GDK_DISPLAY_XDISPLAY (gdk_screen_get_display (screen)); win = XRootWindow (display, GDK_SCREEN_XNUMBER (screen)); current_desktop = XInternAtom (display, "_NET_CURRENT_DESKTOP", True); XGetWindowProperty (display, win, current_desktop, 0, G_MAXLONG, False, XA_CARDINAL, &type, &format, &n_items, &bytes_after, &data_return); if (type == XA_CARDINAL && format == 32 && n_items > 0) workspace = ((long *) data_return)[0]; if (data_return) XFree (data_return); return workspace; }
bool wxTopLevelWindowGTK::Show( bool show ) { wxASSERT_MSG( (m_widget != NULL), wxT("invalid frame") ); #ifdef GDK_WINDOWING_X11 bool deferShow = show && !m_isShown && m_deferShow; if (deferShow) { deferShow = m_deferShowAllowed && gs_requestFrameExtentsStatus != 2 && !gtk_widget_get_realized(m_widget) && g_signal_handler_find(m_widget, GSignalMatchType(G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_DATA), g_signal_lookup("property_notify_event", GTK_TYPE_WIDGET), 0, NULL, NULL, this); if (deferShow) { GdkScreen* screen = gtk_widget_get_screen(m_widget); GdkAtom atom = gdk_atom_intern("_NET_REQUEST_FRAME_EXTENTS", false); deferShow = gdk_x11_screen_supports_net_wm_hint(screen, atom) != 0; // If _NET_REQUEST_FRAME_EXTENTS not supported, don't allow changes // to m_decorSize, it breaks saving/restoring window size with // GetSize()/SetSize() because it makes window bigger between each // restore and save. m_updateDecorSize = deferShow; } m_deferShow = deferShow; } if (deferShow) { // Initial show. If WM supports _NET_REQUEST_FRAME_EXTENTS, defer // calling gtk_widget_show() until _NET_FRAME_EXTENTS property // notification is received, so correct frame extents are known. // This allows resizing m_widget to keep the overall size in sync with // what wxWidgets expects it to be without an obvious change in the // window size immediately after it becomes visible. // Realize m_widget, so m_widget->window can be used. Realizing normally // causes the widget tree to be size_allocated, which generates size // events in the wrong order. However, the size_allocates will not be // done if the allocation is not the default (1,1). GtkAllocation alloc; gtk_widget_get_allocation(m_widget, &alloc); const int alloc_width = alloc.width; if (alloc_width == 1) { alloc.width = 2; gtk_widget_set_allocation(m_widget, &alloc); } gtk_widget_realize(m_widget); if (alloc_width == 1) { alloc.width = 1; gtk_widget_set_allocation(m_widget, &alloc); } // send _NET_REQUEST_FRAME_EXTENTS XClientMessageEvent xevent; memset(&xevent, 0, sizeof(xevent)); xevent.type = ClientMessage; GdkWindow* window = gtk_widget_get_window(m_widget); xevent.window = GDK_WINDOW_XID(window); xevent.message_type = gdk_x11_atom_to_xatom_for_display( gdk_window_get_display(window), gdk_atom_intern("_NET_REQUEST_FRAME_EXTENTS", false)); xevent.format = 32; Display* display = GDK_DISPLAY_XDISPLAY(gdk_window_get_display(window)); XSendEvent(display, DefaultRootWindow(display), false, SubstructureNotifyMask | SubstructureRedirectMask, (XEvent*)&xevent); if (gs_requestFrameExtentsStatus == 0) { // if WM does not respond to request within 1 second, // we assume support for _NET_REQUEST_FRAME_EXTENTS is not working m_netFrameExtentsTimerId = g_timeout_add(1000, request_frame_extents_timeout, this); } // defer calling gtk_widget_show() m_isShown = true; return true; } #endif // GDK_WINDOWING_X11 if (show && !gtk_widget_get_realized(m_widget)) { // size_allocate signals occur in reverse order (bottom to top). // Things work better if the initial wxSizeEvents are sent (from the // top down), before the initial size_allocate signals occur. wxSizeEvent event(GetSize(), GetId()); event.SetEventObject(this); HandleWindowEvent(event); } bool change = base_type::Show(show); if (change && !show) { // make sure window has a non-default position, so when it is shown // again, it won't be repositioned by WM as if it were a new window // Note that this must be done _after_ the window is hidden. gtk_window_move((GtkWindow*)m_widget, m_x, m_y); } return change; }
/* Code to find the active window in order to collect stats for social * application browsing. */ static void get_active_application_properties(HippoIdleMonitor *monitor, char **wm_class, char **title) { Display *xdisplay = GDK_DISPLAY_XDISPLAY(monitor->display); int n_screens = gdk_display_get_n_screens(monitor->display); Atom net_active_window_x = gdk_x11_get_xatom_by_name_for_display(monitor->display, "_NET_ACTIVE_WINDOW"); GdkAtom net_active_window_gdk = gdk_atom_intern("_NET_ACTIVE_WINDOW", FALSE); Window active_window = None; int i; Atom type; int format; unsigned long n_items; unsigned long bytes_after; guchar *data; if (wm_class) *wm_class = NULL; if (title) *title = NULL; /* Find the currently focused window by looking at the _NET_ACTIVE_WINDOW property * on all the screens of the display. */ for (i = 0; i < n_screens; i++) { GdkScreen *screen = gdk_display_get_screen(monitor->display, i); GdkWindow *root = gdk_screen_get_root_window(screen); if (!gdk_x11_screen_supports_net_wm_hint (screen, net_active_window_gdk)) continue; XGetWindowProperty (xdisplay, GDK_DRAWABLE_XID(root), net_active_window_x, 0, 1, False, XA_WINDOW, &type, &format, &n_items, &bytes_after, &data); if (type == XA_WINDOW) { active_window = *(Window *)data; XFree(data); break; } } /* Now that we have the active window, figure out the application name and WM class */ gdk_error_trap_push(); if (active_window && wm_class) { if (XGetWindowProperty (xdisplay, active_window, XA_WM_CLASS, 0, G_MAXLONG, False, XA_STRING, &type, &format, &n_items, &bytes_after, &data) == Success && type == XA_STRING) { if (format == 8) { char **list; int count; count = gdk_text_property_to_utf8_list_for_display(monitor->display, GDK_TARGET_STRING, 8, data, n_items, &list); if (count > 1) *wm_class = g_strdup(list[1]); if (list) g_strfreev(list); } XFree(data); } } if (active_window && title) { Atom utf8_string = gdk_x11_get_xatom_by_name_for_display(monitor->display, "UTF8_STRING"); if (XGetWindowProperty (xdisplay, active_window, gdk_x11_get_xatom_by_name_for_display(monitor->display, "_NET_WM_NAME"), 0, G_MAXLONG, False, utf8_string, &type, &format, &n_items, &bytes_after, &data) == Success && type == utf8_string) { if (format == 8 && g_utf8_validate((char *)data, -1, NULL)) { *title = g_strdup((char *)data); } XFree(data); } } if (active_window && title && *title == NULL) { if (XGetWindowProperty (xdisplay, active_window, XA_WM_NAME, 0, G_MAXLONG, False, AnyPropertyType, &type, &format, &n_items, &bytes_after, &data) == Success && type != None) { if (format == 8) { char **list; int count; count = gdk_text_property_to_utf8_list_for_display(monitor->display, gdk_x11_xatom_to_atom_for_display(monitor->display, type), 8, data, n_items, &list); if (count > 0) *title = g_strdup(list[0]); if (list) g_strfreev(list); } XFree(data); } } gdk_error_trap_pop(); }
int wxSystemSettingsNative::GetMetric( wxSystemMetric index, wxWindow* win ) { guchar *data = NULL; Atom type; int format; gulong nitems; GdkWindow *window = NULL; if(win && GTK_WIDGET_REALIZED(win->GetHandle())) window = win->GetHandle()->window; switch (index) { case wxSYS_BORDER_X: case wxSYS_BORDER_Y: case wxSYS_EDGE_X: case wxSYS_EDGE_Y: case wxSYS_FRAMESIZE_X: case wxSYS_FRAMESIZE_Y: // If a window is specified/realized, and it is a toplevel window, we can query from wm. // The returned border thickness is outside the client area in that case. if (window) { wxTopLevelWindow *tlw = wxDynamicCast(win, wxTopLevelWindow); if (!tlw) return -1; // not a tlw, not sure how to approach else { // Check if wm supports frame extents - we can't know // the border widths if it does not. #if GTK_CHECK_VERSION(2,2,0) if (!gtk_check_version(2,2,0)) { if (!gdk_x11_screen_supports_net_wm_hint( gdk_drawable_get_screen(window), gdk_atom_intern("_NET_FRAME_EXTENTS", false) ) ) return -1; } else #endif { if (!gdk_net_wm_supports(gdk_atom_intern("_NET_FRAME_EXTENTS", false))) return -1; } // Get the frame extents from the windowmanager. // In most cases the top extent is the titlebar, so we use the bottom extent // for the heights. if (wxXGetWindowProperty(window, type, format, nitems, data)) { int border_return = -1; if ((type == XA_CARDINAL) && (format == 32) && (nitems >= 4) && (data)) { switch(index) { case wxSYS_BORDER_X: case wxSYS_EDGE_X: case wxSYS_FRAMESIZE_X: border_return = ((long*)data)[1]; // width of right extent break; default: border_return = ((long*)data)[3]; // height of bottom extent break; } } if (data) XFree(data); return border_return; } } } return -1; // no window specified case wxSYS_CURSOR_X: case wxSYS_CURSOR_Y: #ifdef __WXGTK24__ if (!gtk_check_version(2,4,0)) { if (window) return gdk_display_get_default_cursor_size(gdk_drawable_get_display(window)); else return gdk_display_get_default_cursor_size(gdk_display_get_default()); } else #endif return 16; case wxSYS_DCLICK_X: case wxSYS_DCLICK_Y: gint dclick_distance; #if GTK_CHECK_VERSION(2,2,0) if (window && !gtk_check_version(2,2,0)) g_object_get(gtk_settings_get_for_screen(gdk_drawable_get_screen(window)), "gtk-double-click-distance", &dclick_distance, NULL); else #endif g_object_get(gtk_settings_get_default(), "gtk-double-click-distance", &dclick_distance, NULL); return dclick_distance * 2; case wxSYS_DRAG_X: case wxSYS_DRAG_Y: gint drag_threshold; #if GTK_CHECK_VERSION(2,2,0) if (window && !gtk_check_version(2,2,0)) { g_object_get( gtk_settings_get_for_screen(gdk_drawable_get_screen(window)), "gtk-dnd-drag-threshold", &drag_threshold, NULL); } else #endif { g_object_get(gtk_settings_get_default(), "gtk-dnd-drag-threshold", &drag_threshold, NULL); } // The correct thing here would be to double the value // since that is what the API wants. But the values // are much bigger under GNOME than under Windows and // just seem to much in many cases to be useful. // drag_threshold *= 2; return drag_threshold; // MBN: ditto for icons case wxSYS_ICON_X: return 32; case wxSYS_ICON_Y: return 32; case wxSYS_SCREEN_X: #if GTK_CHECK_VERSION(2,2,0) if (window && !gtk_check_version(2,2,0)) return gdk_screen_get_width(gdk_drawable_get_screen(window)); else #endif return gdk_screen_width(); case wxSYS_SCREEN_Y: #if GTK_CHECK_VERSION(2,2,0) if (window && !gtk_check_version(2,2,0)) return gdk_screen_get_height(gdk_drawable_get_screen(window)); else #endif return gdk_screen_height(); case wxSYS_HSCROLL_Y: return 15; case wxSYS_VSCROLL_X: return 15; case wxSYS_CAPTION_Y: if (!window) // No realized window specified, and no implementation for that case yet. return -1; // Check if wm supports frame extents - we can't know the caption height if it does not. #if GTK_CHECK_VERSION(2,2,0) if (!gtk_check_version(2,2,0)) { if (!gdk_x11_screen_supports_net_wm_hint( gdk_drawable_get_screen(window), gdk_atom_intern("_NET_FRAME_EXTENTS", false) ) ) return -1; } else #endif { if (!gdk_net_wm_supports(gdk_atom_intern("_NET_FRAME_EXTENTS", false))) return -1; } wxASSERT_MSG( wxDynamicCast(win, wxTopLevelWindow), wxT("Asking for caption height of a non toplevel window") ); // Get the height of the top windowmanager border. // This is the titlebar in most cases. The titlebar might be elsewhere, and // we could check which is the thickest wm border to decide on which side the // titlebar is, but this might lead to interesting behaviours in used code. // Reconsider when we have a way to report to the user on which side it is. if (wxXGetWindowProperty(window, type, format, nitems, data)) { int caption_height = -1; if ((type == XA_CARDINAL) && (format == 32) && (nitems >= 3) && (data)) { caption_height = ((long*)data)[2]; // top frame extent } if (data) XFree(data); return caption_height; } // Try a default approach without a window pointer, if possible // ... return -1; case wxSYS_PENWINDOWS_PRESENT: // No MS Windows for Pen computing extension available in X11 based gtk+. return 0; default: return -1; // metric is unknown } }
void gdk_x11_screen_get_work_area (GdkScreen *screen, GdkRectangle *area) { GdkX11Screen *x11_screen = GDK_X11_SCREEN (screen); Atom workarea; Atom type; Window win; int format; gulong num; gulong leftovers; gulong max_len = 4 * 32; guchar *ret_workarea = NULL; long *workareas; int result; int disp_screen; int desktop; Display *display; display = GDK_DISPLAY_XDISPLAY (gdk_screen_get_display (screen)); disp_screen = GDK_SCREEN_XNUMBER (screen); workarea = XInternAtom (display, "_NET_WORKAREA", True); /* Defaults in case of error */ area->x = 0; area->y = 0; area->width = gdk_screen_get_width (screen); area->height = gdk_screen_get_height (screen); if (!gdk_x11_screen_supports_net_wm_hint (screen, gdk_atom_intern_static_string ("_NET_WORKAREA"))) return; if (workarea == None) return; win = XRootWindow (display, disp_screen); result = XGetWindowProperty (display, win, workarea, 0, max_len, False, AnyPropertyType, &type, &format, &num, &leftovers, &ret_workarea); if (result != Success || type == None || format == 0 || leftovers || num % 4 != 0) goto out; desktop = get_current_desktop (screen); if (desktop + 1 > num / 4) /* fvwm gets this wrong */ goto out; workareas = (long *) ret_workarea; area->x = workareas[desktop * 4]; area->y = workareas[desktop * 4 + 1]; area->width = workareas[desktop * 4 + 2]; area->height = workareas[desktop * 4 + 3]; area->x /= x11_screen->window_scale; area->y /= x11_screen->window_scale; area->width /= x11_screen->window_scale; area->height /= x11_screen->window_scale; out: if (ret_workarea) XFree (ret_workarea); }
/* Code to find the active window in order to collect stats for social * application browsing. */ static void get_active_application_properties(HippoIdleMonitor *monitor, char **wm_class, char **title) { Display *xdisplay = GDK_DISPLAY_XDISPLAY(monitor->display); int n_screens = gdk_display_get_n_screens(monitor->display); Atom net_active_window_x = gdk_x11_get_xatom_by_name_for_display(monitor->display, "_NET_ACTIVE_WINDOW"); GdkAtom net_active_window_gdk = gdk_atom_intern("_NET_ACTIVE_WINDOW", FALSE); Window active_window = None; int i; Atom type; int format; unsigned long n_items; unsigned long bytes_after; guchar *data; gboolean is_desktop = FALSE; if (wm_class) *wm_class = NULL; if (title) *title = NULL; /* Find the currently focused window by looking at the _NET_ACTIVE_WINDOW property * on all the screens of the display. */ for (i = 0; i < n_screens; i++) { GdkScreen *screen = gdk_display_get_screen(monitor->display, i); GdkWindow *root = gdk_screen_get_root_window(screen); if (!gdk_x11_screen_supports_net_wm_hint (screen, net_active_window_gdk)) continue; XGetWindowProperty (xdisplay, GDK_DRAWABLE_XID(root), net_active_window_x, 0, 1, False, XA_WINDOW, &type, &format, &n_items, &bytes_after, &data); if (type == XA_WINDOW) { active_window = *(Window *)data; XFree(data); break; } } /* Now that we have the active window, figure out the application name and WM class */ gdk_error_trap_push(); if (active_window && wm_class) { if (XGetWindowProperty (xdisplay, active_window, XA_WM_CLASS, 0, G_MAXLONG, False, XA_STRING, &type, &format, &n_items, &bytes_after, &data) == Success && type == XA_STRING) { if (format == 8) { char **list; int count; count = gdk_text_property_to_utf8_list_for_display(monitor->display, GDK_TARGET_STRING, 8, data, n_items, &list); if (count > 1) { /* This is a check for Nautilus, which sets the instance to this * value for the desktop window; we do this rather than check for * the more general _NET_WM_WINDOW_TYPE_DESKTOP to avoid having * to do another XGetProperty on every iteration. We generally * don't want to count the desktop being focused as application * usage because it frequently can be a false-positive of an * empty workspace. */ if (strcmp(list[0], "desktop_window") == 0) is_desktop = TRUE; else *wm_class = g_strdup(list[1]); } if (list) g_strfreev(list); } XFree(data); } } if (is_desktop) active_window = None; if (active_window && title) { Atom utf8_string = gdk_x11_get_xatom_by_name_for_display(monitor->display, "UTF8_STRING"); if (XGetWindowProperty (xdisplay, active_window, gdk_x11_get_xatom_by_name_for_display(monitor->display, "_NET_WM_NAME"), 0, G_MAXLONG, False, utf8_string, &type, &format, &n_items, &bytes_after, &data) == Success && type == utf8_string) { if (format == 8 && g_utf8_validate((char *)data, -1, NULL)) { *title = g_strdup((char *)data); } XFree(data); } } if (active_window && title && *title == NULL) { if (XGetWindowProperty (xdisplay, active_window, XA_WM_NAME, 0, G_MAXLONG, False, AnyPropertyType, &type, &format, &n_items, &bytes_after, &data) == Success && type != None) { if (format == 8) { char **list; int count; count = gdk_text_property_to_utf8_list_for_display(monitor->display, gdk_x11_xatom_to_atom_for_display(monitor->display, type), 8, data, n_items, &list); if (count > 0) *title = g_strdup(list[0]); if (list) g_strfreev(list); } XFree(data); } } gdk_error_trap_pop(); }