Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
seleniumhq
GitHub Repository: seleniumhq/selenium
Path: blob/trunk/cpp/linux-specific/x_ignore_nofocus.c
2867 views
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
}
764
765