"Fossies" - the Fresh Open Source Software Archive 
Member "selenium-selenium-4.8.1/cpp/linux-specific/x_ignore_nofocus.c" (17 Feb 2023, 21405 Bytes) of package /linux/www/selenium-selenium-4.8.1.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "x_ignore_nofocus.c" see the
Fossies "Dox" file reference documentation.
1 #include <stdio.h>
2 #include <X11/Xlib.h>
3 #include <X11/X.h>
4 #include <dlfcn.h>
5 #include <sys/utsname.h>
6 #include <string.h>
7 #include "print_events.h"
8 #include <time.h>
9 #include <sys/time.h>
10 #include <stdlib.h>
11 #include <assert.h>
12 #include <unistd.h>
13 #include <elf.h>
14
15 #ifndef TRUE
16 #define TRUE 1
17 #endif
18
19 #ifndef FALSE
20 #define FALSE 0
21 #endif
22
23 // Define this to prevent events from being faked.
24 //#undef NO_FAKING
25
26 //#define DEBUG_PRINTOUTS
27
28 #ifdef DEBUG_PRINTOUTS
29 FILE* g_out_stream = 0;
30 #define LOG(...) if (g_out_stream != NULL) { fprintf(g_out_stream, __VA_ARGS__); fflush(g_out_stream); }
31 #define OPEN_LOGGING_FILE { g_out_stream = fopen("/tmp/x_ignore_focus_log.txt", "a+"); }
32 #define CLOSE_LOGGING_FILE { fclose(g_out_stream); g_out_stream = NULL; }
33 #else
34 // This is to prevent compiler warning for unused variables.
35 void do_nothing(const char* fmt, ...) {}
36 #define LOG(...) do_nothing(__VA_ARGS__)
37 #define OPEN_LOGGING_FILE ;
38 #define CLOSE_LOGGING_FILE ;
39 #endif
40
41 int g_library_inited = FALSE;
42
43 struct _FocusKeepStatus {
44 Window active_window;
45 Window new_window;
46 int start_switch_window;
47 int start_close_window;
48 int during_switch;
49 int during_close;
50 int should_steal_focus;
51 int encountered_focus_in_event;
52 int active_window_from_close;
53 };
54
55 typedef struct _FocusKeepStatus FocusKeepStatus;
56
57 void init_focus_keep_struct(FocusKeepStatus* stat)
58 {
59 stat->active_window = 0;
60 stat->new_window = 0;
61 stat->start_switch_window = FALSE;
62 stat->start_close_window = FALSE;
63 stat->during_switch = FALSE;
64 stat->during_close = FALSE;
65 stat->should_steal_focus = FALSE;
66 // This boolean is for remembering if we already had a FocusIn event and
67 // never re-send that event as well, not to break clients which expect to get
68 // FocusOut before FocusIn
69 stat->encountered_focus_in_event = FALSE;
70 // This remembers if the active was learnt due to a close
71 stat->active_window_from_close = FALSE;
72 };
73
74 Window get_active_window(FocusKeepStatus* stat)
75 {
76 return stat->active_window;
77 }
78
79 int is_focus_out(XEvent* ev)
80 {
81 return (ev->type == FocusOut);
82 }
83
84 int is_focus_in(XEvent* ev)
85 {
86 return (ev->type == FocusIn);
87 }
88
89 int is_reparent_notify(XEvent* ev)
90 {
91 return (ev->type == ReparentNotify);
92 }
93
94 int is_destroy_notify(XEvent* ev)
95 {
96 return (ev->type == DestroyNotify);
97 }
98
99 Window extract_window_id(XEvent* ev);
100
101 struct {
102 Window window_id;
103 Window* related_windows;
104 } g_cached_xquerytree;
105
106 void init_cached_xquerytree()
107 {
108 g_cached_xquerytree.window_id = 0;
109 g_cached_xquerytree.related_windows = 0;
110 }
111
112 // Performing XQueryTree after UnmapNotify for some of the
113 // windows will cause a crash. Cache to prevent it.
114 int cache_xquery_result(Display* dpy, Window for_win) {
115 Window root_win = 0;
116 Window parent_win = 0;
117 Window* childs_list = NULL;
118 unsigned int num_childs = 0;
119 int k = 0;
120
121 if ((g_cached_xquerytree.window_id == for_win) &&
122 (g_cached_xquerytree.related_windows != NULL)) {
123 return TRUE;
124 }
125
126 LOG("Invoking XQueryTree for window %#lx\n", for_win);
127 int queryRes = XQueryTree(dpy, for_win, &root_win,
128 &parent_win, &childs_list, &num_childs);
129 if (queryRes == 0) {
130 LOG("XQueryTree failed, rc=%d\n", queryRes);
131 return FALSE;
132 }
133
134 if (g_cached_xquerytree.related_windows != NULL) {
135 free(g_cached_xquerytree.related_windows);
136 g_cached_xquerytree.related_windows = NULL;
137 }
138
139 int numRelatedWindows = (1 /* parent_win */ +
140 1 /* actual win */ + num_childs + 1 /* NULL */);
141
142
143 g_cached_xquerytree.related_windows = malloc(sizeof(Window) * numRelatedWindows);
144 LOG("Allocated at address %p , numRelWindows: %d\n",
145 g_cached_xquerytree.related_windows, numRelatedWindows);
146 int relatedWinsIndex = 0;
147 g_cached_xquerytree.related_windows[relatedWinsIndex++] = parent_win;
148 g_cached_xquerytree.related_windows[relatedWinsIndex++] = for_win;
149
150 if ((num_childs > 0) && (childs_list != NULL)) {
151 for (k = 0; k < num_childs; k++) {
152 g_cached_xquerytree.related_windows[relatedWinsIndex++] = childs_list[k];
153 }
154 XFree(childs_list);
155 childs_list = NULL;
156 }
157 g_cached_xquerytree.related_windows[relatedWinsIndex] = 0;
158
159 g_cached_xquerytree.window_id = for_win;
160
161 return TRUE;
162 }
163
164 int lookup_in_xquery_cache(Window ev_win)
165 {
166 int ret_val = FALSE;
167 int k = 0;
168 if (g_cached_xquerytree.related_windows == NULL) {
169 LOG("related_windows is NULL, cache is inconsistent.\n");
170 return FALSE;
171 }
172 while ((g_cached_xquerytree.related_windows[k] != 0) && (!ret_val)) {
173 if (g_cached_xquerytree.related_windows[k] == ev_win) {
174 ret_val = TRUE;
175 }
176 k++;
177 }
178
179 return ret_val;
180 }
181
182 int window_ids_difference(Window win_one, Window win_two)
183 {
184 return (abs(win_one - win_two));
185 }
186
187 int event_on_active_or_adj_window(Display* dpy, XEvent* ev, Window active_win)
188 {
189 Window ev_win;
190 int ret_val = FALSE;
191
192 ev_win = extract_window_id(ev);
193
194 // This is probably also essential as on focus in events on new windows
195 // XQueryTree should not be called yet.
196 if (active_win == ev_win) {
197 return TRUE;
198 }
199
200 // "Obviously" related windows - ID of active window
201 // and event_window differ by 1. By performing this check first,
202 // we avoid calling XQueryTree which causes a segfault
203 // if the window queried is being closed.
204 if (abs(active_win - ev_win) <= 1) {
205 ret_val = TRUE;
206 } else {
207 if (cache_xquery_result(dpy, active_win)) {
208 ret_val = lookup_in_xquery_cache(ev_win);
209 }
210 }
211
212 return ret_val;
213 }
214
215 #define MAX_BUFFER_SIZE (256)
216
217 void identify_switch_situation(FocusKeepStatus* stat)
218 {
219 if (stat->start_switch_window || stat->start_close_window) {
220 // In the middle of a window switch.
221 Window old_active = get_active_window(stat);
222 stat->active_window = 0;
223 stat->during_switch = TRUE;
224
225 if (stat->start_close_window) {
226 stat->during_close = TRUE;
227 }
228
229 LOG("Window switching detected, active was: %#lx close: %d\n",
230 old_active, stat->during_close);
231
232 // Reset the the flags.
233 stat->start_switch_window = FALSE;
234 stat->start_close_window = FALSE;
235 }
236 }
237
238 void set_active_window(FocusKeepStatus* stat, XEvent* ev)
239 {
240 stat->active_window = extract_window_id(ev);
241 if (stat->during_close) {
242 stat->active_window_from_close = TRUE;
243 } else {
244 stat->active_window_from_close = FALSE;
245 }
246 stat->encountered_focus_in_event = FALSE;
247 stat->during_switch = FALSE;
248 stat->start_switch_window = FALSE;
249 stat->start_close_window = FALSE;
250 LOG("Setting Active Window due to FocusIn: %#lx (from close: %d)\n",
251 get_active_window(stat), stat->active_window_from_close);
252 }
253
254 void identify_new_window_situation(FocusKeepStatus* stat, XEvent* ev)
255 {
256 Window new_win = extract_window_id(ev);
257 assert(is_reparent_notify(ev));
258
259 if (get_active_window(stat) != 0) {
260 stat->new_window = new_win;
261 LOG("New window being created: %#lx\n", stat->new_window);
262 } else {
263 LOG("Reparent notify for window: %#lx, but no active.\n", new_win);
264 }
265 }
266
267 void identify_active_destroyed(FocusKeepStatus* stat, XEvent* ev)
268 {
269 assert(is_destroy_notify(ev));
270
271 if (extract_window_id(ev) == get_active_window(stat)) {
272 LOG("Active window: %#lx is destroyed!\n", get_active_window(stat));
273 stat->active_window = 0;
274 }
275 }
276
277 void steal_focus_back_if_needed(FocusKeepStatus* stat, Display* dpy)
278 {
279 if ((stat->should_steal_focus) && (get_active_window(stat) != 0)) {
280 stat->should_steal_focus = FALSE;
281
282 if ((!stat->during_close) || (stat->active_window_from_close)) {
283 LOG("Stealing focus back to %#lx\n", get_active_window(stat));
284 stat->new_window = 0;
285
286 XSetInputFocus(dpy, get_active_window(stat), RevertToParent, CurrentTime);
287 // Allow a focus in event to flow again to the window considered
288 // active.
289 stat->encountered_focus_in_event = FALSE;
290 } else {
291 LOG("Not stealing focus back. During close: %d Active from close: %d.\n",
292 stat->during_close, stat->active_window_from_close);
293 // Set during_close to false here - This is the point where the state
294 // transition is done - specifically, we consider the entire close
295 // process to be completed.
296 stat->during_close = FALSE;
297 }
298 }
299 }
300
301 int should_discard_focus_out_event(FocusKeepStatus* stat, Display* dpy,
302 XEvent *ev)
303 {
304 int ret_val = FALSE;
305 if (is_focus_out(ev) == FALSE) {
306 return FALSE;
307 }
308
309 const int detail = ev->xfocus.detail;
310
311 if (stat->new_window != 0) {
312 /*
313 if (!(event_on_active_or_adj_window(dpy, ev, stat->new_window)
314 || event_on_active_or_adj_window(dpy, ev, get_active_window(stat)))) {
315 LOG( "ERROR - Event on window %#lx, which is neither new nor active.\n",
316 extract_window_id(ev));
317 } else */ {
318 LOG("Event on new/active (%#lx) during new window creation, allowing.",
319 extract_window_id(ev));
320 LOG(" New: %#lx Active: %#lx\n", stat->new_window, stat->active_window);
321 }
322 return FALSE;
323 }
324
325 if (event_on_active_or_adj_window(dpy, ev, get_active_window(stat))) {
326 // If moving ownership between sub-windows of the same Firefox window.
327 if ((detail == NotifyAncestor) || (detail == NotifyInferior)) {
328 // Allow this one.
329 LOG("Focus will move to ancestor / inferior (%d). Allowing.\n", detail);
330 stat->encountered_focus_in_event = FALSE;
331 } else {
332 // Disallow transfer of focus to outside windows.
333 if (!stat->active_window_from_close) {
334 ret_val = TRUE;
335 } else {
336 LOG("FocusOut event, but active window from close. Not discarding.\n");
337 }
338 }
339 } else {
340 LOG("Got Focus out event on window %#lx but active window is %#lx\n",
341 extract_window_id(ev), get_active_window(stat));
342 }
343
344 return ret_val;
345 }
346
347 int should_discard_focus_in_event(FocusKeepStatus* stat, Display* dpy,
348 XEvent *ev)
349 {
350 int ret_val = FALSE;
351 if (is_focus_in(ev) == FALSE) {
352 return FALSE;
353 }
354
355 // Event not on active window - It's either on a new window currently being
356 // created or on a different firefox one. On the first case, it will
357 // be allowed through, but blocked on the second case.
358 if (!event_on_active_or_adj_window(dpy, ev, get_active_window(stat))) {
359 LOG("Got Focus in event on window %#lx but active window is %#lx\n",
360 extract_window_id(ev), get_active_window(stat));
361
362 if (stat->new_window != 0) {
363 // If we are in the process of a new window creation, do not ignore
364 // this focus in event - allow it both for the new window
365 // and for a child window of it. However, if this is a focus in
366 // event for a child window (not the new window itself), then
367 // steal focus back from it afterwards.
368 ret_val = FALSE;
369 Window curr_win = extract_window_id(ev);
370 if (curr_win == stat->new_window) {
371 LOG("FocusIn event on new window - allowing.\n");
372 } else {
373 //if (event_on_active_or_adj_window(dpy, ev, stat->new_window) == FALSE) {
374 if (window_ids_difference(curr_win, stat->new_window) > 4) {
375 LOG("ERROR - Event on window %#lx\n", extract_window_id(ev));
376 } else {
377 LOG("FocusIn event on child of new window - steal focus!\n");
378 }
379 stat->should_steal_focus = TRUE;
380 }
381 } else {
382 // Second case: No new window creation process disallow focus in
383 ret_val = TRUE;
384 }
385 } else {
386 // Event actually on the active window or an inferior window
387 // of it.
388 if (stat->encountered_focus_in_event == FALSE) {
389 // If a focus in event for this window was not yet encountered,
390 // allow this focus in event and ignore in the future.
391 stat->encountered_focus_in_event = TRUE;
392 ret_val = FALSE;
393 } else {
394 ret_val = TRUE;
395 }
396 }
397
398 return ret_val;
399 }
400
401 #ifndef NO_FAKING
402 // Real functions
403 void fake_keymap_notify_event(XEvent* outEvent, XEvent* sourceEvent)
404 {
405 XEvent ev;
406 ev.type = KeymapNotify;
407 ev.xkeymap.serial = sourceEvent->xfocus.serial;
408 ev.xkeymap.send_event = sourceEvent->xfocus.send_event;
409 ev.xkeymap.display = sourceEvent->xfocus.display;
410 ev.xkeymap.window = sourceEvent->xfocus.window;
411 //bzero(ev.xkeymap.key_vector, 32);
412 *outEvent = ev;
413 }
414
415 #else
416 // Dummy functions - faking will not happen.
417 void fake_keymap_notify_event(XEvent* outEvent, XEvent* sourceEvent)
418 {
419 LOG("*** Not faking keymap notify event.\n");
420 *outEvent = *sourceEvent;
421 }
422
423 static int XSetInputFocus(Display *display, Window focus, int revert_to,
424 Time time)
425 {
426 LOG("*** Not stealing focus.\n");
427 return 1;
428 }
429
430 #endif
431
432 int is_32bit_system()
433 {
434 struct utsname sys_info;
435 int uname_res = uname(&sys_info);
436 // In case of error, arbitrarily decide it is.
437 if (uname_res != 0) {
438 return TRUE;
439 }
440
441 const char arch_64[] = "x86_64";
442 if (strncmp(sys_info.machine, arch_64, strlen(arch_64)) == 0) {
443 return FALSE;
444 }
445
446 return TRUE;
447 }
448
449 int is_emulated_32bit()
450 {
451 #ifdef __i386__
452 return !is_32bit_system();
453 #else
454 return FALSE;
455 #endif
456 }
457
458 #define MAX_LIBRARY_PATH (1024)
459
460 // Returns the window ID from every type of event
461 // that should be handled.
462 Window extract_window_id(XEvent* ev) {
463 switch (ev->type) {
464 case FocusIn:
465 return ev->xfocus.window;
466 break;
467 case FocusOut:
468 return ev->xfocus.window;
469 break;
470 case Expose:
471 return ev->xexpose.window;
472 break;
473 case VisibilityNotify:
474 return ev->xvisibility.window;
475 break;
476 case CreateNotify:
477 return ev->xcreatewindow.window;
478 break;
479 case MapNotify:
480 return ev->xmap.window;
481 break;
482 case PropertyNotify:
483 return ev->xproperty.window;
484 break;
485 case DestroyNotify:
486 return ev->xdestroywindow.window;
487 break;
488 case ConfigureNotify:
489 return ev->xconfigure.window;
490 break;
491 case MotionNotify:
492 return ev->xmotion.window;
493 break;
494 case UnmapNotify:
495 return ev->xunmap.window;
496 break;
497 case EnterNotify:
498 case LeaveNotify:
499 return ev->xcrossing.window;
500 break;
501 case ReparentNotify:
502 return ev->xreparent.window;
503 break;
504 case ClientMessage:
505 return ev->xclient.window;
506 break;
507 case ButtonPress:
508 case ButtonRelease:
509 return ev->xbutton.window;
510 break;
511 case NoExpose:
512 break;
513 default:
514 LOG("Unknown event type %d\n", ev->type);
515 };
516 return 0;
517 }
518
519 int is_library_for_architecture(const char* lib_path, uint16_t arch)
520 {
521 Elf32_Ehdr elf32_header;
522 int elf32_header_size = sizeof(elf32_header);
523
524 FILE* lib = fopen(lib_path, "r");
525 int bytes_read = fread(&elf32_header, 1, elf32_header_size, lib);
526 fclose(lib);
527 lib = NULL;
528
529 if (bytes_read != elf32_header_size) {
530 return FALSE;
531 }
532
533 if ((memcmp(elf32_header.e_ident, ELFMAG, sizeof(ELFMAG) - 1) == 0)
534 && (elf32_header.e_type == ET_DYN) && (elf32_header.e_machine == arch))
535 {
536 return TRUE;
537 }
538
539 return FALSE;
540 }
541
542 int is_usable_library(const char *candidate_library, uint16_t desired_architecture)
543 {
544 if (access(candidate_library, F_OK) == 0 &&
545 is_library_for_architecture(candidate_library, desired_architecture) == TRUE) {
546 void *ret_handle = dlopen(candidate_library, RTLD_LAZY);
547 if (ret_handle == NULL) {
548 return FALSE;
549 }
550 dlclose(ret_handle);
551
552 return TRUE;
553 }
554 return FALSE;
555 }
556
557 int find_xlib_by_arch(const char* possible_locations[],
558 int locations_length, uint16_t desired_architecture)
559 {
560 int i;
561 for (i = 0; i < locations_length; i++) {
562 const char* possible_location = possible_locations[i];
563
564 if (is_usable_library(possible_location, desired_architecture))
565 {
566 return i;
567 }
568 }
569
570 return -1;
571 }
572
573
574 int find_xlib_by_env(char *library, uint16_t desired_architecture)
575 {
576 char *ld_env = getenv("LD_LIBRARY_PATH");
577 if (ld_env == 0) {
578 return FALSE;
579 }
580
581 char *ld_to_parse = strdup(ld_env);
582
583 int found_library = FALSE;
584 char *t = strtok(ld_to_parse, ":");
585 char potential_library[MAX_LIBRARY_PATH + 1];
586
587 while ((t != NULL) && (!found_library)) {
588 snprintf(potential_library, MAX_LIBRARY_PATH, "%s/libX11.so.6", t);
589 if (is_usable_library(potential_library, desired_architecture)) {
590 strcpy(library, potential_library);
591 found_library = TRUE;
592 }
593 t = strtok(NULL, ":");
594 }
595
596 free(ld_to_parse);
597 return found_library;
598 }
599
600 void* get_xlib_handle()
601 {
602 void* ret_handle = NULL;
603 char library[MAX_LIBRARY_PATH + 1];
604
605 const char * possible_locations[] = {
606 "/usr/lib/libX11.so.6", //default_x11_location
607 "/usr/lib/x86_64-linux-gnu/libX11.so.6", //debian_x11_location
608 "/usr/lib/i386-linux-gnu/libX11.so.6", //ubuntu_32bit_x11_location
609 "/usr/lib64/libX11.so.6", //opensuse_x11_location
610 "/usr/lib32/libX11.so.6"
611 };
612 int locations_len = sizeof(possible_locations) / sizeof(char*);
613
614 uint16_t required_lib_arch;
615 if (is_32bit_system() || is_emulated_32bit()) {
616 required_lib_arch = EM_386;
617 } else {
618 required_lib_arch = EM_X86_64;
619 }
620 int suitable_xlib_index = find_xlib_by_arch(possible_locations, locations_len, required_lib_arch);
621 int found_library = FALSE;
622 if (suitable_xlib_index >= 0) {
623 snprintf(library, MAX_LIBRARY_PATH, "%s", possible_locations[suitable_xlib_index]);
624 found_library = TRUE;
625 } else {
626 found_library = find_xlib_by_env(library, required_lib_arch);
627 }
628 if (found_library == FALSE) {
629 const char* desired_arch = (required_lib_arch == EM_386 ? "32-bit" : "64-bit");
630 fprintf(stderr, "None of the following is a %s version of Xlib:", desired_arch);
631 int i;
632 for (i = 0; i < locations_len; i++) {
633 fprintf(stderr, " %s\n", possible_locations[i]);
634 }
635 return NULL;
636 }
637
638 ret_handle = dlopen(library, RTLD_LAZY);
639 if (ret_handle == NULL) {
640 fprintf(stderr, "Failed to dlopen %s\n", library);
641 fprintf(stderr, "dlerror says: %s\n", dlerror());
642 }
643
644 return ret_handle;
645 }
646
647 void print_event_to_log(Display* dpy, XEvent* ev)
648 {
649 #ifdef DEBUG_PRINTOUTS
650 if ((ev->type != PropertyNotify) && (ev->type != ConfigureNotify)) {
651 print_event(g_out_stream, ev, dpy);
652 }
653 #endif
654 }
655
656 // This global variable is intentionally declared here - as I wish the rest
657 // of the functions will act on it as a parameter.
658 FocusKeepStatus g_focus_status;
659
660 void initFocusStatusAndXQueryTree() {
661 if (g_library_inited == FALSE) {
662 LOG("Library initialized.\n");
663 g_library_inited = TRUE;
664 init_cached_xquerytree();
665 init_focus_keep_struct(&g_focus_status);
666 }
667 }
668
669 int XNextEvent(Display *display, XEvent *outEvent) {
670 // Code to pull the real function handle from X11 library.
671 void *handle = NULL;
672
673 //This will turn the function proto into a function pointer declaration
674 int (*real_func)(Display *display, XEvent *outEvent) = NULL;
675 handle = get_xlib_handle();
676
677 if (handle == NULL) {
678 return -1;
679 }
680
681 // The real event from XNextEvent
682 XEvent realEvent;
683
684 // Find the real function.
685 real_func = dlsym(handle, "XNextEvent");
686 // Invoke the real function.
687 int rf_ret = real_func(display, &realEvent);
688
689 OPEN_LOGGING_FILE;
690
691 initFocusStatusAndXQueryTree();
692
693 // This display object will be used to inquire X server
694 // about inferior and parent windows.
695 Display* dpy = display;
696 //assert(dpy != NULL);
697
698 print_event_to_log(dpy, &realEvent);
699
700 // Is the event on a window other than the active one?
701 // If so, update gActiveWindow on two cases:
702 // 1. It's the first window known to the module.
703 // 2. It's the second window known to the module. The second
704 // window is the actual browser window (the first one is just a
705 // set-up one).
706 //
707 if ((get_active_window(&g_focus_status) == 0) && (is_focus_in(&realEvent))) {
708 set_active_window(&g_focus_status, &realEvent);
709 } else {
710 identify_switch_situation(&g_focus_status);
711 }
712
713 if (is_reparent_notify(&realEvent)) {
714 identify_new_window_situation(&g_focus_status, &realEvent);
715 }
716
717 if (is_destroy_notify(&realEvent)) {
718 identify_active_destroyed(&g_focus_status, &realEvent);
719 }
720
721 if ((g_focus_status.during_switch == TRUE) ||
722 (get_active_window(&g_focus_status) == 0)) {
723 LOG("During switch: %d Active win: %#lx during close: %d\n",
724 g_focus_status.during_switch, get_active_window(&g_focus_status),
725 g_focus_status.during_close);
726 *outEvent = realEvent;
727 } else if (should_discard_focus_out_event(&g_focus_status, dpy, &realEvent)) {
728 // Fake an event!
729 fake_keymap_notify_event(outEvent, &realEvent);
730 LOG("Fake event for focus out.\n");
731 } else if (should_discard_focus_in_event(&g_focus_status, dpy, &realEvent)) {
732 fake_keymap_notify_event(outEvent, &realEvent);
733 LOG("Fake event for focus in.\n");
734 } else {
735 *outEvent = realEvent;
736 }
737
738 steal_focus_back_if_needed(&g_focus_status, dpy);
739
740 dlclose(handle);
741 CLOSE_LOGGING_FILE;
742 return rf_ret;
743 }
744
745 void notify_of_switch_to_window(long window_id) {
746 initFocusStatusAndXQueryTree();
747 g_focus_status.start_switch_window = TRUE;
748 OPEN_LOGGING_FILE;
749 LOG("Notify of switch-to-window with id %d\n", window_id);
750 CLOSE_LOGGING_FILE;
751 }
752
753 void notify_of_close_window(long window_id) {
754 initFocusStatusAndXQueryTree();
755 g_focus_status.start_close_window = TRUE;
756 OPEN_LOGGING_FILE;
757 if (0 == window_id) {
758 LOG("Notify of close-all-windows.\n");
759 } else {
760 LOG("Notify of close-window with id %n", window_id);
761 }
762 CLOSE_LOGGING_FILE;
763 }