108
108
static void client_call_notifies(ObClient *self, GSList *list);
109
109
static void client_ping_event(ObClient *self, gboolean dead);
110
110
static void client_prompt_kill(ObClient *self);
111
static gboolean client_can_steal_focus(ObClient *self, Time steal_time,
111
static gboolean client_can_steal_focus(ObClient *self,
112
gboolean allow_other_desktop,
113
gboolean request_from_user,
114
Time steal_time, Time launch_time);
114
116
void client_startup(gboolean reconfig)
116
if ((client_default_icon = RrImageCacheFind(ob_rr_icons,
117
ob_rr_theme->def_win_icon,
118
ob_rr_theme->def_win_icon_w,
119
ob_rr_theme->def_win_icon_h)))
120
RrImageRef(client_default_icon);
122
client_default_icon = RrImageNew(ob_rr_icons);
123
RrImageAddPicture(client_default_icon,
124
ob_rr_theme->def_win_icon,
125
ob_rr_theme->def_win_icon_w,
126
ob_rr_theme->def_win_icon_h);
118
client_default_icon = RrImageNewFromData(
119
ob_rr_icons, ob_rr_theme->def_win_icon,
120
ob_rr_theme->def_win_icon_w, ob_rr_theme->def_win_icon_h);
129
122
if (reconfig) return;
196
189
stacking_set_list();
199
void client_manage_all(void)
204
XWindowAttributes attrib;
206
XQueryTree(ob_display, RootWindow(ob_display, ob_screen),
207
&w, &w, &children, &nchild);
209
/* remove all icon windows from the list */
210
for (i = 0; i < nchild; i++) {
211
if (children[i] == None) continue;
212
wmhints = XGetWMHints(ob_display, children[i]);
214
if ((wmhints->flags & IconWindowHint) &&
215
(wmhints->icon_window != children[i]))
216
for (j = 0; j < nchild; j++)
217
if (children[j] == wmhints->icon_window) {
225
/* manage windows in reverse order from how they were originally mapped.
226
this is an attempt to manage children windows before their parents, so
227
that when the parent is mapped, it can find the child */
228
for (i = 0; i < nchild; ++i) {
229
if (children[i] == None)
231
if (XGetWindowAttributes(ob_display, children[i], &attrib)) {
232
if (attrib.override_redirect) continue;
234
if (attrib.map_state != IsUnmapped)
235
client_manage(children[i], NULL);
241
192
void client_manage(Window window, ObPrompt *prompt)
245
XWindowAttributes attrib;
246
195
XSetWindowAttributes attrib_set;
248
gboolean activate = FALSE;
196
gboolean try_activate = FALSE;
197
gboolean do_activate;
249
198
ObAppSettings *settings;
250
199
gboolean transient = FALSE;
251
Rect place, *monitor;
252
Time launch_time, map_time;
253
202
guint32 user_time;
257
/* check if it has already been unmapped by the time we started
258
mapping. the grab does a sync so we don't have to here */
259
if (XCheckTypedWindowEvent(ob_display, window, DestroyNotify, &e) ||
260
XCheckTypedWindowEvent(ob_display, window, UnmapNotify, &e))
262
XPutBackEvent(ob_display, &e);
264
ob_debug("Trying to manage unmapped window. Aborting that.\n");
266
return; /* don't manage it */
269
/* make sure it isn't an override-redirect window */
270
if (!XGetWindowAttributes(ob_display, window, &attrib) ||
271
attrib.override_redirect)
274
return; /* don't manage it */
277
/* is the window a docking app */
278
if ((wmhint = XGetWMHints(ob_display, window))) {
279
if ((wmhint->flags & StateHint) &&
280
wmhint->initial_state == WithdrawnState)
282
dock_add(window, wmhint);
290
ob_debug("Managing window: 0x%lx\n", window);
292
map_time = event_get_server_time();
205
ob_debug("Managing window: 0x%lx", window);
294
207
/* choose the events we want to receive on the CLIENT window
295
208
(ObPrompt windows can request events too) */
296
209
attrib_set.event_mask = CLIENT_EVENTMASK |
297
210
(prompt ? prompt->event_mask : 0);
298
211
attrib_set.do_not_propagate_mask = CLIENT_NOPROPAGATEMASK;
299
XChangeWindowAttributes(ob_display, window,
212
XChangeWindowAttributes(obt_display, window,
300
213
CWEventMask|CWDontPropagate, &attrib_set);
302
215
/* create the ObClient struct, and populate it from the hints on the
304
self = g_new0(ObClient, 1);
305
self->obwin.type = Window_Client;
217
self = g_slice_new0(ObClient);
218
self->obwin.type = OB_WINDOW_CLASS_CLIENT;
306
219
self->window = window;
307
220
self->prompt = prompt;
308
221
self->managed = TRUE;
315
228
/* get all the stuff off the window */
316
229
client_get_all(self, TRUE);
318
ob_debug("Window type: %d\n", self->type);
319
ob_debug("Window group: 0x%x\n", self->group?self->group->leader:0);
320
ob_debug("Window name: %s class: %s role: %s\n", self->name, self->class, self->role);
231
ob_debug("Window type: %d", self->type);
232
ob_debug("Window group: 0x%x", self->group?self->group->leader:0);
233
ob_debug("Window name: %s class: %s role: %s title: %s",
234
self->name, self->class, self->role, self->title);
322
236
/* per-app settings override stuff from client_get_all, and return the
323
237
settings for other uses too. the returned settings is a shallow copy,
324
238
that needs to be freed with g_free(). */
325
239
settings = client_get_settings_state(self);
327
/* now we have all of the window's information so we can set this up.
328
do this before creating the frame, so it can tell that we are still
329
mapping and doesn't go applying things right away */
330
client_setup_decor_and_functions(self, FALSE);
332
241
/* specify that if we exit, the window should not be destroyed and
333
242
should be reparented back to root automatically, unless we are managing
334
243
an internal ObPrompt window */
335
244
if (!self->prompt)
336
XChangeSaveSet(ob_display, window, SetModeInsert);
245
XChangeSaveSet(obt_display, window, SetModeInsert);
338
247
/* create the decoration frame for the client window */
339
248
self->frame = frame_new(self);
499
437
client_apply_startup_state(self, place.x, place.y,
500
438
place.width, place.height);
505
ob_debug_type(OB_DEBUG_FOCUS, "Going to try activate new window? %s\n",
506
activate ? "yes" : "no");
508
activate = client_can_steal_focus(self, map_time, launch_time);
440
/* set the initial value of the desktop hint, when one wasn't requested
442
OBT_PROP_SET32(self->window, NET_WM_DESKTOP, CARDINAL, self->desktop);
444
/* grab mouse bindings before showing the window */
445
mouse_grab_for_client(self, TRUE);
447
/* this has to happen before we try focus the window, but we want it to
448
happen after the client's stacking has been determined or it looks bad
452
if (!config_focus_under_mouse)
453
ignore_start = event_start_ignore_all_enters();
457
if (!config_focus_under_mouse)
458
event_end_ignore_all_enters(ignore_start);
461
/* activate/hilight/raise the window */
464
gboolean stacked = client_restore_session_stacking(self);
465
client_present(self, FALSE, !stacked, TRUE);
511
468
/* if the client isn't stealing focus, then hilite it so the user
512
469
knows it is there, but don't do this if we're restoring from a
721
655
if (ob_state() != OB_STATE_EXITING) {
722
656
/* these values should not be persisted across a window
723
657
unmapping/mapping */
724
PROP_ERASE(self->window, net_wm_desktop);
725
PROP_ERASE(self->window, net_wm_state);
726
PROP_ERASE(self->window, wm_state);
658
OBT_PROP_ERASE(self->window, NET_WM_DESKTOP);
659
OBT_PROP_ERASE(self->window, NET_WM_STATE);
660
OBT_PROP_ERASE(self->window, WM_STATE);
728
662
/* if we're left in an unmapped state, the client wont be mapped.
729
663
this is bad, since we will no longer be managing the window on
731
XMapWindow(ob_display, self->window);
665
XMapWindow(obt_display, self->window);
734
668
/* these should not be left on the window ever. other window managers
735
669
don't necessarily use them and it will mess them up (like compiz) */
736
PROP_ERASE(self->window, net_wm_visible_name);
737
PROP_ERASE(self->window, net_wm_visible_icon_name);
670
OBT_PROP_ERASE(self->window, NET_WM_VISIBLE_NAME);
671
OBT_PROP_ERASE(self->window, NET_WM_VISIBLE_ICON_NAME);
739
673
/* update the list hints */
740
674
client_set_list();
742
ob_debug("Unmanaged window 0x%lx\n", self->window);
676
ob_debug("Unmanaged window 0x%lx", self->window);
744
678
/* free all data allocated in the client struct */
745
679
RrImageUnref(self->icon_set);
762
696
/* this is all that got allocated to get the decorations */
764
698
frame_free(self->frame);
699
g_slice_free(ObClient, self);
768
static gboolean client_can_steal_focus(ObClient *self, Time steal_time,
702
static gboolean client_can_steal_focus(ObClient *self,
703
gboolean allow_other_desktop,
704
gboolean request_from_user,
769
706
Time launch_time)
772
709
gboolean relative_focused;
773
gboolean parent_focused;
777
parent_focused = (focus_client != NULL &&
778
client_search_focus_parent(self));
779
713
relative_focused = (focus_client != NULL &&
780
714
(client_search_focus_tree_full(self) != NULL ||
781
715
client_search_focus_group_full(self) != NULL));
783
717
/* This is focus stealing prevention */
784
ob_debug_type(OB_DEBUG_FOCUS,
785
"Want to focus window 0x%x at time %u "
786
"launched at %u (last user interaction time %u)\n",
787
self->window, steal_time, launch_time,
788
event_last_user_time);
790
/* if it's on another desktop */
718
ob_debug("Want to focus window 0x%x at time %u "
719
"launched at %u (last user interaction time %u) "
720
"request from %s, allow other desktop: %s",
721
self->window, steal_time, launch_time,
722
event_last_user_time,
723
(request_from_user ? "user" : "other"),
724
(allow_other_desktop ? "yes" : "no"));
727
if no launch time is provided for an application, make one up.
729
if the window is related to other existing windows
730
and one of those windows was the last used
731
then we will give it a launch time equal to the last user time,
732
which will end up giving the window focus probably.
734
the window is related to other windows, but you are not working in
736
seems suspicious, so we will give it a launch time of
737
NOW - STEAL_INTERVAL,
738
so it will be given focus only if we didn't use something else
739
during the steal interval.
741
the window is all on its own, so we can't judge it. give it a launch
742
time equal to the last user time, so it will probably take focus.
744
this way running things from a terminal will give them focus, but popups
745
without a launch time shouldn't steal focus so easily.
749
if (client_has_relative(self)) {
750
if (event_last_user_time && client_search_focus_group_full(self)) {
751
/* our relative is focused */
752
launch_time = event_last_user_time;
753
ob_debug("Unknown launch time, using %u - window in active "
754
"group", launch_time);
756
else if (!request_from_user) {
757
/* has relatives which are not being used. suspicious */
758
launch_time = event_time() - OB_EVENT_USER_TIME_DELAY;
759
ob_debug("Unknown launch time, using %u - window in inactive "
760
"group", launch_time);
763
/* has relatives which are not being used, but the user seems
764
to want to go there! */
765
launch_time = event_last_user_time;
766
ob_debug("Unknown launch time, using %u - user request",
771
/* the window is on its own, probably the user knows it is going
773
launch_time = event_last_user_time;
774
ob_debug("Unknown launch time, using %u - independent window",
779
/* if it's on another desktop
780
then if allow_other_desktop is true, we don't want to let it steal
781
focus, unless it was launched after we changed desktops and the request
791
784
if (!(self->desktop == screen_desktop ||
792
785
self->desktop == DESKTOP_ALL) &&
793
/* the timestamp is from before you changed desktops */
795
(screen_desktop_user_time &&
786
(!allow_other_desktop ||
787
(request_from_user && screen_desktop_user_time &&
796
788
!event_time_after(launch_time, screen_desktop_user_time))))
799
ob_debug_type(OB_DEBUG_FOCUS,
800
"Not focusing the window because its on another "
791
ob_debug("Not focusing the window because its on another desktop\n");
803
793
/* If something is focused... */
804
794
else if (focus_client) {
805
795
/* If the user is working in another window right now, then don't
807
if (!parent_focused &&
808
event_last_user_time && launch_time &&
809
event_time_after(event_last_user_time, launch_time) &&
810
event_last_user_time != launch_time &&
797
if (!relative_focused &&
798
event_last_user_time &&
799
/* last user time must be strictly > launch_time to block focus */
800
(event_time_after(event_last_user_time, launch_time) &&
801
event_last_user_time != launch_time) &&
811
802
event_time_after(event_last_user_time,
812
803
steal_time - OB_EVENT_USER_TIME_DELAY))
815
ob_debug_type(OB_DEBUG_FOCUS,
816
"Not focusing the window because the user is "
817
"working in another window that is not "
820
/* If the new window is a transient (and its relatives aren't
822
else if (client_has_parent(self) && !relative_focused) {
824
ob_debug_type(OB_DEBUG_FOCUS,
825
"Not focusing the window because it is a "
826
"transient, and its relatives aren't focused\n");
828
/* Don't steal focus from globally active clients.
829
I stole this idea from KWin. It seems nice.
831
else if (!(focus_client->can_focus ||
832
focus_client->focus_notify))
835
ob_debug_type(OB_DEBUG_FOCUS,
836
"Not focusing the window because a globally "
837
"active client has focus\n");
806
ob_debug("Not focusing the window because the user is "
807
"working in another window that is not its relative");
839
809
/* Don't move focus if it's not going to go to this window
841
811
else if (client_focus_target(self) != self) {
843
ob_debug_type(OB_DEBUG_FOCUS,
844
"Not focusing the window because another window "
845
"would get the focus anyway\n");
813
ob_debug("Not focusing the window because another window "
814
"would get the focus anyway");
847
/* Don't move focus if the window is not visible on the current
848
desktop and none of its relatives are focused */
849
else if (!(self->desktop == screen_desktop ||
850
self->desktop == DESKTOP_ALL) &&
854
ob_debug_type(OB_DEBUG_FOCUS,
855
"Not focusing the window because it is on "
856
"another desktop and no relatives are focused ");
816
/* For requests that don't come from the user */
817
else if (!request_from_user) {
818
/* If the new window is a transient (and its relatives aren't
820
if (client_has_parent(self) && !relative_focused) {
822
ob_debug("Not focusing the window because it is a "
823
"transient, and its relatives aren't focused");
825
/* Don't steal focus from globally active clients.
826
I stole this idea from KWin. It seems nice.
828
else if (!(focus_client->can_focus || focus_client->focus_notify))
831
ob_debug("Not focusing the window because a globally "
832
"active client has focus");
834
/* Don't move focus if the window is not visible on the current
835
desktop and none of its relatives are focused */
836
else if (!allow_other_desktop &&
837
!screen_compare_desktops(self->desktop, screen_desktop) &&
841
ob_debug("Not focusing the window because it is on "
842
"another desktop and no relatives are focused ");
861
ob_debug_type(OB_DEBUG_FOCUS,
862
"Focus stealing prevention activated for %s at "
863
"time %u (last user interaction time %u)\n",
864
self->title, steal_time, event_last_user_time);
848
ob_debug("Focus stealing prevention activated for %s at "
849
"time %u (last user interaction time %u)",
850
self->title, steal_time, event_last_user_time);
852
ob_debug("Allowing focus stealing for %s at time %u (last user "
853
"interaction time %u)",
854
self->title, steal_time, event_last_user_time);
1287
1289
guint32 *state;
1290
if (PROP_GETA32(self->window, net_wm_state, atom, &state, &num)) {
1292
if (OBT_PROP_GETA32(self->window, NET_WM_STATE, ATOM, &state, &num)) {
1292
1294
for (i = 0; i < num; ++i) {
1293
if (state[i] == prop_atoms.net_wm_state_modal)
1295
if (state[i] == OBT_PROP_ATOM(NET_WM_STATE_MODAL))
1294
1296
self->modal = TRUE;
1295
else if (state[i] == prop_atoms.net_wm_state_shaded)
1297
else if (state[i] == OBT_PROP_ATOM(NET_WM_STATE_SHADED))
1296
1298
self->shaded = TRUE;
1297
else if (state[i] == prop_atoms.net_wm_state_hidden)
1299
else if (state[i] == OBT_PROP_ATOM(NET_WM_STATE_HIDDEN))
1298
1300
self->iconic = TRUE;
1299
else if (state[i] == prop_atoms.net_wm_state_skip_taskbar)
1301
else if (state[i] == OBT_PROP_ATOM(NET_WM_STATE_SKIP_TASKBAR))
1300
1302
self->skip_taskbar = TRUE;
1301
else if (state[i] == prop_atoms.net_wm_state_skip_pager)
1303
else if (state[i] == OBT_PROP_ATOM(NET_WM_STATE_SKIP_PAGER))
1302
1304
self->skip_pager = TRUE;
1303
else if (state[i] == prop_atoms.net_wm_state_fullscreen)
1305
else if (state[i] == OBT_PROP_ATOM(NET_WM_STATE_FULLSCREEN))
1304
1306
self->fullscreen = TRUE;
1305
else if (state[i] == prop_atoms.net_wm_state_maximized_vert)
1307
else if (state[i] == OBT_PROP_ATOM(NET_WM_STATE_MAXIMIZED_VERT))
1306
1308
self->max_vert = TRUE;
1307
else if (state[i] == prop_atoms.net_wm_state_maximized_horz)
1309
else if (state[i] == OBT_PROP_ATOM(NET_WM_STATE_MAXIMIZED_HORZ))
1308
1310
self->max_horz = TRUE;
1309
else if (state[i] == prop_atoms.net_wm_state_above)
1311
else if (state[i] == OBT_PROP_ATOM(NET_WM_STATE_ABOVE))
1310
1312
self->above = TRUE;
1311
else if (state[i] == prop_atoms.net_wm_state_below)
1313
else if (state[i] == OBT_PROP_ATOM(NET_WM_STATE_BELOW))
1312
1314
self->below = TRUE;
1313
else if (state[i] == prop_atoms.net_wm_state_demands_attention)
1315
else if (state[i] == OBT_PROP_ATOM(NET_WM_STATE_DEMANDS_ATTENTION))
1314
1316
self->demands_attention = TRUE;
1315
else if (state[i] == prop_atoms.ob_wm_state_undecorated)
1317
else if (state[i] == OBT_PROP_ATOM(OB_WM_STATE_UNDECORATED))
1316
1318
self->undecorated = TRUE;
1515
1517
self->type = -1;
1516
1518
self->transient = FALSE;
1518
if (PROP_GETA32(self->window, net_wm_window_type, atom, &val, &num)) {
1520
if (OBT_PROP_GETA32(self->window, NET_WM_WINDOW_TYPE, ATOM, &val, &num)) {
1519
1521
/* use the first value that we know about in the array */
1520
1522
for (i = 0; i < num; ++i) {
1521
if (val[i] == prop_atoms.net_wm_window_type_desktop)
1523
if (val[i] == OBT_PROP_ATOM(NET_WM_WINDOW_TYPE_DESKTOP))
1522
1524
self->type = OB_CLIENT_TYPE_DESKTOP;
1523
else if (val[i] == prop_atoms.net_wm_window_type_dock)
1525
else if (val[i] == OBT_PROP_ATOM(NET_WM_WINDOW_TYPE_DOCK))
1524
1526
self->type = OB_CLIENT_TYPE_DOCK;
1525
else if (val[i] == prop_atoms.net_wm_window_type_toolbar)
1527
else if (val[i] == OBT_PROP_ATOM(NET_WM_WINDOW_TYPE_TOOLBAR))
1526
1528
self->type = OB_CLIENT_TYPE_TOOLBAR;
1527
else if (val[i] == prop_atoms.net_wm_window_type_menu)
1529
else if (val[i] == OBT_PROP_ATOM(NET_WM_WINDOW_TYPE_MENU))
1528
1530
self->type = OB_CLIENT_TYPE_MENU;
1529
else if (val[i] == prop_atoms.net_wm_window_type_utility)
1531
else if (val[i] == OBT_PROP_ATOM(NET_WM_WINDOW_TYPE_UTILITY))
1530
1532
self->type = OB_CLIENT_TYPE_UTILITY;
1531
else if (val[i] == prop_atoms.net_wm_window_type_splash)
1533
else if (val[i] == OBT_PROP_ATOM(NET_WM_WINDOW_TYPE_SPLASH))
1532
1534
self->type = OB_CLIENT_TYPE_SPLASH;
1533
else if (val[i] == prop_atoms.net_wm_window_type_dialog)
1535
else if (val[i] == OBT_PROP_ATOM(NET_WM_WINDOW_TYPE_DIALOG))
1534
1536
self->type = OB_CLIENT_TYPE_DIALOG;
1535
else if (val[i] == prop_atoms.net_wm_window_type_normal)
1537
else if (val[i] == OBT_PROP_ATOM(NET_WM_WINDOW_TYPE_NORMAL))
1536
1538
self->type = OB_CLIENT_TYPE_NORMAL;
1537
else if (val[i] == prop_atoms.kde_net_wm_window_type_override) {
1539
else if (val[i] == OBT_PROP_ATOM(KDE_NET_WM_WINDOW_TYPE_OVERRIDE))
1538
1541
/* prevent this window from getting any decor or
1539
1542
functionality */
1540
1543
self->mwmhints.flags &= (OB_MWM_FLAG_FUNCTIONS |
1574
1577
void client_update_protocols(ObClient *self)
1576
1579
guint32 *proto;
1577
guint num_return, i;
1579
1582
self->focus_notify = FALSE;
1580
1583
self->delete_window = FALSE;
1582
if (PROP_GETA32(self->window, wm_protocols, atom, &proto, &num_return)) {
1583
for (i = 0; i < num_return; ++i) {
1584
if (proto[i] == prop_atoms.wm_delete_window)
1585
if (OBT_PROP_GETA32(self->window, WM_PROTOCOLS, ATOM, &proto, &num_ret)) {
1586
for (i = 0; i < num_ret; ++i) {
1587
if (proto[i] == OBT_PROP_ATOM(WM_DELETE_WINDOW))
1585
1588
/* this means we can request the window to close */
1586
1589
self->delete_window = TRUE;
1587
else if (proto[i] == prop_atoms.wm_take_focus)
1590
else if (proto[i] == OBT_PROP_ATOM(WM_TAKE_FOCUS))
1588
1591
/* if this protocol is requested, then the window will be
1589
1592
notified whenever we want it to receive focus */
1590
1593
self->focus_notify = TRUE;
1591
else if (proto[i] == prop_atoms.net_wm_ping)
1594
else if (proto[i] == OBT_PROP_ATOM(NET_WM_PING))
1592
1595
/* if this protocol is requested, then the window will allow
1593
1596
pings to determine if it is still alive */
1594
1597
self->ping = TRUE;
1596
else if (proto[i] == prop_atoms.net_wm_sync_request)
1599
else if (proto[i] == OBT_PROP_ATOM(NET_WM_SYNC_REQUEST))
1597
1600
/* if this protocol is requested, then resizing the
1598
1601
window will be synchronized between the frame and the
1866
1879
/* desktop windows are kept on all desktops */
1867
1880
if (self->type != OB_CLIENT_TYPE_DESKTOP)
1868
actions[num++] = prop_atoms.net_wm_action_change_desktop;
1881
actions[num++] = OBT_PROP_ATOM(NET_WM_ACTION_CHANGE_DESKTOP);
1870
1883
if (self->functions & OB_CLIENT_FUNC_SHADE)
1871
actions[num++] = prop_atoms.net_wm_action_shade;
1884
actions[num++] = OBT_PROP_ATOM(NET_WM_ACTION_SHADE);
1872
1885
if (self->functions & OB_CLIENT_FUNC_CLOSE)
1873
actions[num++] = prop_atoms.net_wm_action_close;
1886
actions[num++] = OBT_PROP_ATOM(NET_WM_ACTION_CLOSE);
1874
1887
if (self->functions & OB_CLIENT_FUNC_MOVE)
1875
actions[num++] = prop_atoms.net_wm_action_move;
1888
actions[num++] = OBT_PROP_ATOM(NET_WM_ACTION_MOVE);
1876
1889
if (self->functions & OB_CLIENT_FUNC_ICONIFY)
1877
actions[num++] = prop_atoms.net_wm_action_minimize;
1890
actions[num++] = OBT_PROP_ATOM(NET_WM_ACTION_MINIMIZE);
1878
1891
if (self->functions & OB_CLIENT_FUNC_RESIZE)
1879
actions[num++] = prop_atoms.net_wm_action_resize;
1892
actions[num++] = OBT_PROP_ATOM(NET_WM_ACTION_RESIZE);
1880
1893
if (self->functions & OB_CLIENT_FUNC_FULLSCREEN)
1881
actions[num++] = prop_atoms.net_wm_action_fullscreen;
1894
actions[num++] = OBT_PROP_ATOM(NET_WM_ACTION_FULLSCREEN);
1882
1895
if (self->functions & OB_CLIENT_FUNC_MAXIMIZE) {
1883
actions[num++] = prop_atoms.net_wm_action_maximize_horz;
1884
actions[num++] = prop_atoms.net_wm_action_maximize_vert;
1896
actions[num++] = OBT_PROP_ATOM(NET_WM_ACTION_MAXIMIZE_HORZ);
1897
actions[num++] = OBT_PROP_ATOM(NET_WM_ACTION_MAXIMIZE_VERT);
1886
1899
if (self->functions & OB_CLIENT_FUNC_ABOVE)
1887
actions[num++] = prop_atoms.net_wm_action_above;
1900
actions[num++] = OBT_PROP_ATOM(NET_WM_ACTION_ABOVE);
1888
1901
if (self->functions & OB_CLIENT_FUNC_BELOW)
1889
actions[num++] = prop_atoms.net_wm_action_below;
1902
actions[num++] = OBT_PROP_ATOM(NET_WM_ACTION_BELOW);
1890
1903
if (self->functions & OB_CLIENT_FUNC_UNDECORATE)
1891
actions[num++] = prop_atoms.ob_wm_action_undecorate;
1893
PROP_SETA32(self->window, net_wm_allowed_actions, atom, actions, num);
1895
/* make sure the window isn't breaking any rules now
1897
don't check ICONIFY here. just cuz a window can't iconify doesnt mean
1898
it can't be iconified with its parent
1904
actions[num++] = OBT_PROP_ATOM(OB_WM_ACTION_UNDECORATE);
1906
OBT_PROP_SETA32(self->window, NET_WM_ALLOWED_ACTIONS, ATOM, actions, num);
1908
/* make sure the window isn't breaking any rules now
1910
don't check ICONIFY here. just cuz a window can't iconify doesnt mean
1911
it can't be iconified with its parent
1901
1914
if (!(self->functions & OB_CLIENT_FUNC_SHADE) && self->shaded) {
1902
1915
if (self->frame) client_shade(self, FALSE);
2443
2427
if (self->modal)
2444
netstate[num++] = prop_atoms.net_wm_state_modal;
2428
netstate[num++] = OBT_PROP_ATOM(NET_WM_STATE_MODAL);
2445
2429
if (self->shaded)
2446
netstate[num++] = prop_atoms.net_wm_state_shaded;
2430
netstate[num++] = OBT_PROP_ATOM(NET_WM_STATE_SHADED);
2447
2431
if (self->iconic)
2448
netstate[num++] = prop_atoms.net_wm_state_hidden;
2432
netstate[num++] = OBT_PROP_ATOM(NET_WM_STATE_HIDDEN);
2449
2433
if (self->skip_taskbar)
2450
netstate[num++] = prop_atoms.net_wm_state_skip_taskbar;
2434
netstate[num++] = OBT_PROP_ATOM(NET_WM_STATE_SKIP_TASKBAR);
2451
2435
if (self->skip_pager)
2452
netstate[num++] = prop_atoms.net_wm_state_skip_pager;
2436
netstate[num++] = OBT_PROP_ATOM(NET_WM_STATE_SKIP_PAGER);
2453
2437
if (self->fullscreen)
2454
netstate[num++] = prop_atoms.net_wm_state_fullscreen;
2438
netstate[num++] = OBT_PROP_ATOM(NET_WM_STATE_FULLSCREEN);
2455
2439
if (self->max_vert)
2456
netstate[num++] = prop_atoms.net_wm_state_maximized_vert;
2440
netstate[num++] = OBT_PROP_ATOM(NET_WM_STATE_MAXIMIZED_VERT);
2457
2441
if (self->max_horz)
2458
netstate[num++] = prop_atoms.net_wm_state_maximized_horz;
2442
netstate[num++] = OBT_PROP_ATOM(NET_WM_STATE_MAXIMIZED_HORZ);
2459
2443
if (self->above)
2460
netstate[num++] = prop_atoms.net_wm_state_above;
2444
netstate[num++] = OBT_PROP_ATOM(NET_WM_STATE_ABOVE);
2461
2445
if (self->below)
2462
netstate[num++] = prop_atoms.net_wm_state_below;
2446
netstate[num++] = OBT_PROP_ATOM(NET_WM_STATE_BELOW);
2463
2447
if (self->demands_attention)
2464
netstate[num++] = prop_atoms.net_wm_state_demands_attention;
2448
netstate[num++] = OBT_PROP_ATOM(NET_WM_STATE_DEMANDS_ATTENTION);
2465
2449
if (self->undecorated)
2466
netstate[num++] = prop_atoms.ob_wm_state_undecorated;
2467
PROP_SETA32(self->window, net_wm_state, atom, netstate, num);
2450
netstate[num++] = OBT_PROP_ATOM(OB_WM_STATE_UNDECORATED);
2451
OBT_PROP_SETA32(self->window, NET_WM_STATE, ATOM, netstate, num);
2469
2453
if (self->frame)
2470
2454
frame_adjust_state(self->frame);
3128
3135
When user = FALSE, then the request is coming from the application
3129
3136
itself, and we are more strict about when to send a synthetic
3130
3137
ConfigureNotify. We strictly follow the rules of the ICCCM sec 4.1.5
3131
in this case (if force_reply is true)
3138
in this case (or send one if force_reply is true)
3133
3140
When user = TRUE, then the request is coming from "us", like when we
3134
3141
maximize a window or something. In this case we are more lenient. We
3135
3142
used to follow the same rules as above, but _Java_ Swing can't handle
3136
3143
this. So just to appease Swing, when user = TRUE, we always send
3137
3144
a synthetic ConfigureNotify to give the window its root coordinates.
3145
Lastly, if force_reply is TRUE, we always send a
3146
ConfigureNotify, which is needed during a resize with XSYNCronization.
3139
3148
if ((!user && !resized && (rootmoved || force_reply)) ||
3140
(user && final && rootmoved))
3149
(user && ((!resized && force_reply) || (final && rootmoved))))
3144
3153
event.type = ConfigureNotify;
3145
event.xconfigure.display = ob_display;
3154
event.xconfigure.display = obt_display;
3146
3155
event.xconfigure.event = self->window;
3147
3156
event.xconfigure.window = self->window;
3149
ob_debug("Sending ConfigureNotify to %s for %d,%d %dx%d\n",
3158
ob_debug("Sending ConfigureNotify to %s for %d,%d %dx%d",
3150
3159
self->title, self->root_pos.x, self->root_pos.y, w, h);
3152
3161
/* root window real coords */
3664
static gboolean client_validate_unmap(ObClient *self, int n)
3692
struct ObClientFindDestroyUnmap {
3697
static gboolean find_destroy_unmap(XEvent *e, gpointer data)
3667
gboolean ret = TRUE;
3669
if (XCheckTypedWindowEvent(ob_display, self->window, UnmapNotify, &e)) {
3670
if (n < self->ignore_unmaps) // ignore this one, but look for more
3671
ret = client_validate_unmap(self, n+1);
3673
ret = FALSE; // the window is going to become unmanaged
3675
/* put them back on the event stack so they end up in the same order */
3676
XPutBackEvent(ob_display, &e);
3699
struct ObClientFindDestroyUnmap *find = data;
3700
if (e->type == DestroyNotify)
3701
return e->xdestroywindow.window == find->window;
3702
if (e->type == UnmapNotify && e->xunmap.window == find->window)
3703
/* ignore the first $find->ignore_unmaps$ many unmap events */
3704
return --find->ignore_unmaps < 0;
3682
3708
gboolean client_validate(ObClient *self)
3686
XSync(ob_display, FALSE); /* get all events on the server */
3688
if (XCheckTypedWindowEvent(ob_display, self->window, DestroyNotify, &e)) {
3689
XPutBackEvent(ob_display, &e);
3693
if (!client_validate_unmap(self, 0))
3710
struct ObClientFindDestroyUnmap find;
3712
XSync(obt_display, FALSE); /* get all events on the server */
3714
find.window = self->window;
3715
find.ignore_unmaps = self->ignore_unmaps;
3716
if (xqueue_exists_local(find_destroy_unmap, &find))
3736
3760
if (!state) continue;
3738
3762
/* if toggling, then pick whether we're adding or removing */
3739
if (action == prop_atoms.net_wm_state_toggle) {
3740
if (state == prop_atoms.net_wm_state_modal)
3741
action = modal ? prop_atoms.net_wm_state_remove :
3742
prop_atoms.net_wm_state_add;
3743
else if (state == prop_atoms.net_wm_state_maximized_vert)
3744
action = self->max_vert ? prop_atoms.net_wm_state_remove :
3745
prop_atoms.net_wm_state_add;
3746
else if (state == prop_atoms.net_wm_state_maximized_horz)
3747
action = self->max_horz ? prop_atoms.net_wm_state_remove :
3748
prop_atoms.net_wm_state_add;
3749
else if (state == prop_atoms.net_wm_state_shaded)
3750
action = shaded ? prop_atoms.net_wm_state_remove :
3751
prop_atoms.net_wm_state_add;
3752
else if (state == prop_atoms.net_wm_state_skip_taskbar)
3753
action = self->skip_taskbar ?
3754
prop_atoms.net_wm_state_remove :
3755
prop_atoms.net_wm_state_add;
3756
else if (state == prop_atoms.net_wm_state_skip_pager)
3757
action = self->skip_pager ?
3758
prop_atoms.net_wm_state_remove :
3759
prop_atoms.net_wm_state_add;
3760
else if (state == prop_atoms.net_wm_state_hidden)
3761
action = self->iconic ?
3762
prop_atoms.net_wm_state_remove :
3763
prop_atoms.net_wm_state_add;
3764
else if (state == prop_atoms.net_wm_state_fullscreen)
3765
action = fullscreen ?
3766
prop_atoms.net_wm_state_remove :
3767
prop_atoms.net_wm_state_add;
3768
else if (state == prop_atoms.net_wm_state_above)
3769
action = self->above ? prop_atoms.net_wm_state_remove :
3770
prop_atoms.net_wm_state_add;
3771
else if (state == prop_atoms.net_wm_state_below)
3772
action = self->below ? prop_atoms.net_wm_state_remove :
3773
prop_atoms.net_wm_state_add;
3774
else if (state == prop_atoms.net_wm_state_demands_attention)
3775
action = self->demands_attention ?
3776
prop_atoms.net_wm_state_remove :
3777
prop_atoms.net_wm_state_add;
3778
else if (state == prop_atoms.ob_wm_state_undecorated)
3779
action = undecorated ? prop_atoms.net_wm_state_remove :
3780
prop_atoms.net_wm_state_add;
3763
if (action == OBT_PROP_ATOM(NET_WM_STATE_TOGGLE)) {
3764
if (state == OBT_PROP_ATOM(NET_WM_STATE_MODAL))
3766
else if (state == OBT_PROP_ATOM(NET_WM_STATE_MAXIMIZED_VERT))
3767
value = self->max_vert;
3768
else if (state == OBT_PROP_ATOM(NET_WM_STATE_MAXIMIZED_HORZ))
3769
value = self->max_horz;
3770
else if (state == OBT_PROP_ATOM(NET_WM_STATE_SHADED))
3772
else if (state == OBT_PROP_ATOM(NET_WM_STATE_SKIP_TASKBAR))
3773
value = self->skip_taskbar;
3774
else if (state == OBT_PROP_ATOM(NET_WM_STATE_SKIP_PAGER))
3775
value = self->skip_pager;
3776
else if (state == OBT_PROP_ATOM(NET_WM_STATE_HIDDEN))
3777
value = self->iconic;
3778
else if (state == OBT_PROP_ATOM(NET_WM_STATE_FULLSCREEN))
3780
else if (state == OBT_PROP_ATOM(NET_WM_STATE_ABOVE))
3781
value = self->above;
3782
else if (state == OBT_PROP_ATOM(NET_WM_STATE_BELOW))
3783
value = self->below;
3784
else if (state == OBT_PROP_ATOM(NET_WM_STATE_DEMANDS_ATTENTION))
3785
value = self->demands_attention;
3786
else if (state == OBT_PROP_ATOM(OB_WM_STATE_UNDECORATED))
3787
value = undecorated;
3789
g_assert_not_reached();
3790
action = value ? OBT_PROP_ATOM(NET_WM_STATE_REMOVE) :
3791
OBT_PROP_ATOM(NET_WM_STATE_ADD);
3783
if (action == prop_atoms.net_wm_state_add) {
3784
if (state == prop_atoms.net_wm_state_modal) {
3786
} else if (state == prop_atoms.net_wm_state_maximized_vert) {
3788
} else if (state == prop_atoms.net_wm_state_maximized_horz) {
3790
} else if (state == prop_atoms.net_wm_state_shaded) {
3792
} else if (state == prop_atoms.net_wm_state_skip_taskbar) {
3793
self->skip_taskbar = TRUE;
3794
} else if (state == prop_atoms.net_wm_state_skip_pager) {
3795
self->skip_pager = TRUE;
3796
} else if (state == prop_atoms.net_wm_state_hidden) {
3798
} else if (state == prop_atoms.net_wm_state_fullscreen) {
3800
} else if (state == prop_atoms.net_wm_state_above) {
3803
} else if (state == prop_atoms.net_wm_state_below) {
3806
} else if (state == prop_atoms.net_wm_state_demands_attention) {
3807
demands_attention = TRUE;
3808
} else if (state == prop_atoms.ob_wm_state_undecorated) {
3812
} else { /* action == prop_atoms.net_wm_state_remove */
3813
if (state == prop_atoms.net_wm_state_modal) {
3815
} else if (state == prop_atoms.net_wm_state_maximized_vert) {
3817
} else if (state == prop_atoms.net_wm_state_maximized_horz) {
3819
} else if (state == prop_atoms.net_wm_state_shaded) {
3821
} else if (state == prop_atoms.net_wm_state_skip_taskbar) {
3822
self->skip_taskbar = FALSE;
3823
} else if (state == prop_atoms.net_wm_state_skip_pager) {
3824
self->skip_pager = FALSE;
3825
} else if (state == prop_atoms.net_wm_state_hidden) {
3827
} else if (state == prop_atoms.net_wm_state_fullscreen) {
3829
} else if (state == prop_atoms.net_wm_state_above) {
3831
} else if (state == prop_atoms.net_wm_state_below) {
3833
} else if (state == prop_atoms.net_wm_state_demands_attention) {
3834
demands_attention = FALSE;
3835
} else if (state == prop_atoms.ob_wm_state_undecorated) {
3836
undecorated = FALSE;
3794
value = action == OBT_PROP_ATOM(NET_WM_STATE_ADD);
3795
if (state == OBT_PROP_ATOM(NET_WM_STATE_MODAL)) {
3797
} else if (state == OBT_PROP_ATOM(NET_WM_STATE_MAXIMIZED_VERT)) {
3799
} else if (state == OBT_PROP_ATOM(NET_WM_STATE_MAXIMIZED_HORZ)) {
3801
} else if (state == OBT_PROP_ATOM(NET_WM_STATE_SHADED)) {
3803
} else if (state == OBT_PROP_ATOM(NET_WM_STATE_SKIP_TASKBAR)) {
3804
self->skip_taskbar = value;
3805
} else if (state == OBT_PROP_ATOM(NET_WM_STATE_SKIP_PAGER)) {
3806
self->skip_pager = value;
3807
} else if (state == OBT_PROP_ATOM(NET_WM_STATE_HIDDEN)) {
3809
} else if (state == OBT_PROP_ATOM(NET_WM_STATE_FULLSCREEN)) {
3811
} else if (state == OBT_PROP_ATOM(NET_WM_STATE_ABOVE)) {
3813
/* only unset below when setting above, otherwise you can't get to
3817
} else if (state == OBT_PROP_ATOM(NET_WM_STATE_BELOW)) {
3818
/* and vice versa */
3822
} else if (state == OBT_PROP_ATOM(NET_WM_STATE_DEMANDS_ATTENTION)){
3823
demands_attention = value;
3824
} else if (state == OBT_PROP_ATOM(OB_WM_STATE_UNDECORATED)) {
3825
undecorated = value;
3927
3917
if (!client_can_focus(self)) {
3928
3918
ob_debug_type(OB_DEBUG_FOCUS,
3929
"Client %s can't be focused\n", self->title);
3919
"Client %s can't be focused", self->title);
3933
3923
ob_debug_type(OB_DEBUG_FOCUS,
3934
"Focusing client \"%s\" (0x%x) at time %u\n",
3935
self->title, self->window, event_curtime);
3924
"Focusing client \"%s\" (0x%x) at time %u",
3925
self->title, self->window, event_time());
3937
3927
/* if using focus_delay, stop the timer now so that focus doesn't
3938
3928
go moving on us */
3939
3929
event_halt_focus_delay();
3941
xerror_set_ignore(TRUE);
3942
xerror_occured = FALSE;
3931
obt_display_ignore_errors(TRUE);
3944
3933
if (self->can_focus) {
3945
3934
/* This can cause a BadMatch error with CurrentTime, or if an app
3946
3935
passed in a bad time for _NET_WM_ACTIVE_WINDOW. */
3947
XSetInputFocus(ob_display, self->window, RevertToPointerRoot,
3936
XSetInputFocus(obt_display, self->window, RevertToPointerRoot,
3951
3940
if (self->focus_notify) {
3953
3942
ce.xclient.type = ClientMessage;
3954
ce.xclient.message_type = prop_atoms.wm_protocols;
3955
ce.xclient.display = ob_display;
3943
ce.xclient.message_type = OBT_PROP_ATOM(WM_PROTOCOLS);
3944
ce.xclient.display = obt_display;
3956
3945
ce.xclient.window = self->window;
3957
3946
ce.xclient.format = 32;
3958
ce.xclient.data.l[0] = prop_atoms.wm_take_focus;
3959
ce.xclient.data.l[1] = event_curtime;
3947
ce.xclient.data.l[0] = OBT_PROP_ATOM(WM_TAKE_FOCUS);
3948
ce.xclient.data.l[1] = event_time();
3960
3949
ce.xclient.data.l[2] = 0l;
3961
3950
ce.xclient.data.l[3] = 0l;
3962
3951
ce.xclient.data.l[4] = 0l;
3963
XSendEvent(ob_display, self->window, FALSE, NoEventMask, &ce);
3952
XSendEvent(obt_display, self->window, FALSE, NoEventMask, &ce);
3966
xerror_set_ignore(FALSE);
3955
obt_display_ignore_errors(FALSE);
3968
ob_debug_type(OB_DEBUG_FOCUS, "Error focusing? %d\n", xerror_occured);
3969
return !xerror_occured;
3957
ob_debug_type(OB_DEBUG_FOCUS, "Error focusing? %d",
3958
obt_display_error_occured);
3959
return !obt_display_error_occured;
3972
3962
static void client_present(ObClient *self, gboolean here, gboolean raise,