144 | | handle = g_ascii_strtoll (self->pv->caller_window, &end, 10); |
145 | | if (!end || *end != '\0') { |
| 146 | display = gtk_widget_get_display (GTK_WIDGET (self)); |
| 147 | transient_for = NULL; |
| 148 | handle = 0; |
| 149 | end = NULL; |
| 150 | #ifdef GDK_WINDOWING_X11 |
| 151 | if (GDK_IS_X11_DISPLAY (display)) { |
| 152 | handle = g_ascii_strtoll (self->pv->caller_window, &end, 10); |
| 153 | if (end && *end == '\0') { |
| 154 | transient_for = gdk_x11_window_foreign_new_for_display (display, (Window)handle); |
| 155 | if (transient_for == NULL) { |
| 156 | g_warning ("caller-window property doesn't represent a window on current display: %s", |
| 157 | self->pv->caller_window); |
| 158 | } |
| 159 | } |
| 160 | } |
| 161 | #endif |
| 162 | if (transient_for == NULL) { |
| 163 | transient_for = gcr_prompt_util_window_of_mock_id (self->pv->caller_window); |
| 164 | if (transient_for) { g_object_ref(transient_for); } |
| 165 | } |
| 166 | if (transient_for == NULL) { |
428 | | at = event ? gdk_event_get_time (event) : GDK_CURRENT_TIME; |
429 | | status = gdk_device_grab (device, gtk_widget_get_window (widget), |
430 | | GDK_OWNERSHIP_APPLICATION, TRUE, |
431 | | GDK_KEY_PRESS | GDK_KEY_RELEASE, NULL, at); |
| 432 | status = gdk_seat_grab (seat, gtk_widget_get_window (widget), |
| 433 | GDK_SEAT_CAPABILITY_KEYBOARD, TRUE, |
| 434 | NULL, event, NULL, NULL); |
| 968 | |
| 969 | #define MOCK_HANDLE_LENGTH 24 |
| 970 | typedef struct { |
| 971 | GdkWindow *win; |
| 972 | gchar han[MOCK_HANDLE_LENGTH]; |
| 973 | } MockHandleEntry; |
| 974 | |
| 975 | static GArray * |
| 976 | mock_handle_table() { |
| 977 | static GArray *the_table = NULL; |
| 978 | if (the_table == NULL) { |
| 979 | the_table = g_array_new (FALSE, FALSE, sizeof(MockHandleEntry)); |
| 980 | } |
| 981 | return the_table; |
| 982 | } |
| 983 | |
| 984 | static const gchar * |
| 985 | mock_handle_header() { |
| 986 | static gchar the_header[16]; |
| 987 | static gboolean inited = FALSE; |
| 988 | if (!inited) { |
| 989 | g_snprintf (the_header, sizeof (the_header), "mh%ul", g_random_int()); |
| 990 | inited = TRUE; |
| 991 | } |
| 992 | return the_header; |
| 993 | } |
| 994 | |
| 995 | /** |
| 996 | * gcr_prompt_util_mock_id_of_window: |
| 997 | * @window: the GdkWindow |
| 998 | * |
| 999 | * Return a pointer to memory maintained internally by gcr_prompt which gives |
| 1000 | * a mock string id for the given window, such that later passing a matching string to |
| 1001 | * gcr_prompt_util_window_of_mock_id will give back the same GdkWindow, as long as bpth |
| 1002 | * functions are called within the same process. |
| 1003 | * |
| 1004 | * Useful as an argument to gcr_prompt_set_caller_window for handling caller windows within |
| 1005 | * the same process if no backend handles that allow windows to be identified across |
| 1006 | * processes are available. |
| 1007 | */ |
| 1008 | const gchar * |
| 1009 | gcr_prompt_util_mock_id_of_window (GdkWindow *window) |
| 1010 | { |
| 1011 | GArray *table = mock_handle_table(); |
| 1012 | guint i; |
| 1013 | guint cursize = table->len; |
| 1014 | gsize h; |
| 1015 | MockHandleEntry maybeNewEntry; |
| 1016 | |
| 1017 | /* linear search: not expecting many prompts in a given process */ |
| 1018 | for (i = 0; i < cursize; ++i) { |
| 1019 | if (g_array_index (table, MockHandleEntry,i).win == window) { |
| 1020 | return g_array_index (table, MockHandleEntry,i).han; |
| 1021 | } |
| 1022 | } |
| 1023 | /* haven't seen this window yet, make a new entry */ |
| 1024 | maybeNewEntry.win = window; |
| 1025 | h = g_strlcpy(maybeNewEntry.han, mock_handle_header(), MOCK_HANDLE_LENGTH); |
| 1026 | g_snprintf(maybeNewEntry.han + h, MOCK_HANDLE_LENGTH - h, "%ul", cursize); |
| 1027 | g_array_append_val (table, maybeNewEntry); |
| 1028 | return g_array_index (table, MockHandleEntry, cursize).han; |
| 1029 | } |
| 1030 | |
| 1031 | /** |
| 1032 | * gcr_prompt_util_window_of_mock_id: |
| 1033 | * @try_handle: string to attempt to interpret as a mock handle |
| 1034 | * |
| 1035 | * If gcr_prompt_util_mock_id_of_window earlier in the same process returned a string |
| 1036 | * matching the argument to this function, return the GdkWindow* that |
| 1037 | * gcr_prompt_util_mock_id_of_window was called with, otherwise NULL. |
| 1038 | * |
| 1039 | * The pair of functions gcr_prompt_util_mock_id_of_window and |
| 1040 | * gcr_prompt_util_window_of_mock_id attempt to ensure that a mock handle issued by another |
| 1041 | * process will not be misconstrued as a mock handle for the current process. |
| 1042 | */ |
| 1043 | GdkWindow * |
| 1044 | gcr_prompt_util_window_of_mock_id (const gchar *try_handle) |
| 1045 | { |
| 1046 | static guint h = 0; |
| 1047 | GArray *table; |
| 1048 | guint64 scanned; |
| 1049 | |
| 1050 | if (h == 0) { |
| 1051 | h = strlen (mock_handle_header()); |
| 1052 | } |
| 1053 | if (!g_str_has_prefix (try_handle, mock_handle_header())) { |
| 1054 | return NULL; |
| 1055 | } |
| 1056 | if (!g_ascii_isdigit (try_handle[h])) { |
| 1057 | return NULL; |
| 1058 | } |
| 1059 | scanned = g_ascii_strtoull (try_handle + h, NULL, 10); |
| 1060 | table = mock_handle_table(); |
| 1061 | if (scanned >= table->len) { |
| 1062 | return NULL; |
| 1063 | } |
| 1064 | return g_array_index (table, MockHandleEntry, scanned).win; |
| 1065 | } |