diff options
-rw-r--r-- | ChangeLog | 5 | ||||
-rw-r--r-- | src/Screen.cc | 1 | ||||
-rw-r--r-- | src/Screen.hh | 2 | ||||
-rw-r--r-- | src/Window.cc | 86 | ||||
-rw-r--r-- | src/Window.hh | 6 |
5 files changed, 61 insertions, 39 deletions
@@ -1,5 +1,10 @@ | |||
1 | (Format: Year/Month/Day) | 1 | (Format: Year/Month/Day) |
2 | Changes for 1.1: | 2 | Changes for 1.1: |
3 | *07/05/16: | ||
4 | * Added new resource session.screen<N>.noFocusWhileTypingDelay: <int> (Mark) | ||
5 | - specifies a time in milliseconds that new windows should not gain focus | ||
6 | while the user is typing in the focused window | ||
7 | Window.cc/hh Screen.cc/hh | ||
3 | *07/05/13: | 8 | *07/05/13: |
4 | * Added new placement policies {Row,Col}MinOverlapPlacement. They behave the | 9 | * Added new placement policies {Row,Col}MinOverlapPlacement. They behave the |
5 | same as {Row,Col}SmartPlacement when the window fits but fall back on | 10 | same as {Row,Col}SmartPlacement when the window fits but fall back on |
diff --git a/src/Screen.cc b/src/Screen.cc index 786daa1..2c24157 100644 --- a/src/Screen.cc +++ b/src/Screen.cc | |||
@@ -293,6 +293,7 @@ BScreen::ScreenResource::ScreenResource(FbTk::ResourceManager &rm, | |||
293 | resize_model(rm, BOTTOMRESIZE, scrname+".resizeMode", altscrname+".ResizeMode"), | 293 | resize_model(rm, BOTTOMRESIZE, scrname+".resizeMode", altscrname+".ResizeMode"), |
294 | tab_placement(rm, FbWinFrame::TOPLEFT, scrname+".tab.placement", altscrname+".Tab.Placement"), | 294 | tab_placement(rm, FbWinFrame::TOPLEFT, scrname+".tab.placement", altscrname+".Tab.Placement"), |
295 | windowmenufile(rm, "", scrname+".windowMenu", altscrname+".WindowMenu"), | 295 | windowmenufile(rm, "", scrname+".windowMenu", altscrname+".WindowMenu"), |
296 | typing_delay(rm, 0, scrname+".noFocusWhileTypingDelay", altscrname+".NoFocusWhileTypingDelay"), | ||
296 | user_follow_model(rm, FOLLOW_ACTIVE_WINDOW, scrname+".userFollowModel", altscrname+".UserFollowModel"), | 297 | user_follow_model(rm, FOLLOW_ACTIVE_WINDOW, scrname+".userFollowModel", altscrname+".UserFollowModel"), |
297 | workspaces(rm, 1, scrname+".workspaces", altscrname+".Workspaces"), | 298 | workspaces(rm, 1, scrname+".workspaces", altscrname+".Workspaces"), |
298 | edge_snap_threshold(rm, 0, scrname+".edgeSnapThreshold", altscrname+".EdgeSnapThreshold"), | 299 | edge_snap_threshold(rm, 0, scrname+".edgeSnapThreshold", altscrname+".EdgeSnapThreshold"), |
diff --git a/src/Screen.hh b/src/Screen.hh index b459f3f..2d1c31d 100644 --- a/src/Screen.hh +++ b/src/Screen.hh | |||
@@ -143,6 +143,7 @@ public: | |||
143 | 143 | ||
144 | ResizeModel getResizeModel() const { return *resource.resize_model; } | 144 | ResizeModel getResizeModel() const { return *resource.resize_model; } |
145 | 145 | ||
146 | inline unsigned int noFocusWhileTypingDelay() const { return *resource.typing_delay; } | ||
146 | inline FollowModel getUserFollowModel() const { return *resource.user_follow_model; } | 147 | inline FollowModel getUserFollowModel() const { return *resource.user_follow_model; } |
147 | 148 | ||
148 | inline const std::string &getScrollAction() const { return *resource.scroll_action; } | 149 | inline const std::string &getScrollAction() const { return *resource.scroll_action; } |
@@ -567,6 +568,7 @@ private: | |||
567 | FbTk::Resource<ResizeModel> resize_model; | 568 | FbTk::Resource<ResizeModel> resize_model; |
568 | FbTk::Resource<FbWinFrame::TabPlacement> tab_placement; | 569 | FbTk::Resource<FbWinFrame::TabPlacement> tab_placement; |
569 | FbTk::Resource<std::string> windowmenufile; | 570 | FbTk::Resource<std::string> windowmenufile; |
571 | FbTk::Resource<unsigned int> typing_delay; | ||
570 | FbTk::Resource<FollowModel> user_follow_model; | 572 | FbTk::Resource<FollowModel> user_follow_model; |
571 | bool ordered_dither; | 573 | bool ordered_dither; |
572 | FbTk::Resource<int> workspaces, edge_snap_threshold, focused_alpha, | 574 | FbTk::Resource<int> workspaces, edge_snap_threshold, focused_alpha, |
diff --git a/src/Window.cc b/src/Window.cc index b9e26bd..b9dd4a6 100644 --- a/src/Window.cc +++ b/src/Window.cc | |||
@@ -1363,10 +1363,8 @@ bool FluxboxWindow::focus() { | |||
1363 | if (screen().currentWorkspaceID() != workspaceNumber() && !isStuck()) { | 1363 | if (screen().currentWorkspaceID() != workspaceNumber() && !isStuck()) { |
1364 | 1364 | ||
1365 | BScreen::FollowModel model = screen().getUserFollowModel(); | 1365 | BScreen::FollowModel model = screen().getUserFollowModel(); |
1366 | if (model == BScreen::IGNORE_OTHER_WORKSPACES) { | 1366 | if (model == BScreen::IGNORE_OTHER_WORKSPACES) |
1367 | Fluxbox::instance()->attentionHandler().addAttention(*this); | ||
1368 | return false; | 1367 | return false; |
1369 | } | ||
1370 | 1368 | ||
1371 | // fetch the window to the current workspace | 1369 | // fetch the window to the current workspace |
1372 | if (model == BScreen::FETCH_ACTIVE_WINDOW || | 1370 | if (model == BScreen::FETCH_ACTIVE_WINDOW || |
@@ -1378,10 +1376,11 @@ bool FluxboxWindow::focus() { | |||
1378 | } | 1376 | } |
1379 | 1377 | ||
1380 | FluxboxWindow *cur = FocusControl::focusedFbWindow(); | 1378 | FluxboxWindow *cur = FocusControl::focusedFbWindow(); |
1381 | if (cur && cur != this && cur->isFullscreen()) { | 1379 | WinClient *client = FocusControl::focusedWindow(); |
1382 | Fluxbox::instance()->attentionHandler().addAttention(*this); | 1380 | if (cur && client && cur != this && |
1381 | getRootTransientFor(m_client) != getRootTransientFor(client) && | ||
1382 | (cur->isFullscreen() || cur->isTyping())) | ||
1383 | return false; | 1383 | return false; |
1384 | } | ||
1385 | 1384 | ||
1386 | if (isIconic()) { | 1385 | if (isIconic()) { |
1387 | deiconify(); | 1386 | deiconify(); |
@@ -1463,6 +1462,7 @@ void FluxboxWindow::hide(bool interrupt_moving) { | |||
1463 | 1462 | ||
1464 | void FluxboxWindow::show() { | 1463 | void FluxboxWindow::show() { |
1465 | frame().show(); | 1464 | frame().show(); |
1465 | setState(NormalState, false); | ||
1466 | } | 1466 | } |
1467 | 1467 | ||
1468 | void FluxboxWindow::toggleIconic() { | 1468 | void FluxboxWindow::toggleIconic() { |
@@ -1484,8 +1484,6 @@ void FluxboxWindow::iconify() { | |||
1484 | 1484 | ||
1485 | iconic = true; | 1485 | iconic = true; |
1486 | 1486 | ||
1487 | setState(IconicState, false); | ||
1488 | |||
1489 | hide(true); | 1487 | hide(true); |
1490 | 1488 | ||
1491 | screen().focusControl().setFocusBack(this); | 1489 | screen().focusControl().setFocusBack(this); |
@@ -1494,9 +1492,6 @@ void FluxboxWindow::iconify() { | |||
1494 | const ClientList::iterator client_it_end = m_clientlist.end(); | 1492 | const ClientList::iterator client_it_end = m_clientlist.end(); |
1495 | for (; client_it != client_it_end; ++client_it) { | 1493 | for (; client_it != client_it_end; ++client_it) { |
1496 | WinClient &client = *(*client_it); | 1494 | WinClient &client = *(*client_it); |
1497 | client.setEventMask(NoEventMask); | ||
1498 | client.hide(); | ||
1499 | client.setEventMask(PropertyChangeMask | StructureNotifyMask | FocusChangeMask); | ||
1500 | if (client.transientFor() && | 1495 | if (client.transientFor() && |
1501 | client.transientFor()->fbwindow()) { | 1496 | client.transientFor()->fbwindow()) { |
1502 | if (!client.transientFor()->fbwindow()->isIconic()) { | 1497 | if (!client.transientFor()->fbwindow()->isIconic()) { |
@@ -1535,19 +1530,10 @@ void FluxboxWindow::deiconify(bool reassoc, bool do_raise) { | |||
1535 | m_blackbox_attrib.flags &= ~ATTRIB_HIDDEN; | 1530 | m_blackbox_attrib.flags &= ~ATTRIB_HIDDEN; |
1536 | iconic = false; | 1531 | iconic = false; |
1537 | 1532 | ||
1538 | setState(NormalState, false); | ||
1539 | |||
1540 | ClientList::iterator client_it = clientList().begin(); | ||
1541 | ClientList::iterator client_it_end = clientList().end(); | ||
1542 | for (; client_it != client_it_end; ++client_it) { | ||
1543 | (*client_it)->setEventMask(NoEventMask); | ||
1544 | (*client_it)->show(); | ||
1545 | (*client_it)->setEventMask(PropertyChangeMask | StructureNotifyMask | FocusChangeMask); | ||
1546 | } | ||
1547 | |||
1548 | if (reassoc && !m_client->transients.empty()) { | 1533 | if (reassoc && !m_client->transients.empty()) { |
1549 | // deiconify all transients | 1534 | // deiconify all transients |
1550 | client_it = clientList().begin(); | 1535 | ClientList::iterator client_it = clientList().begin(); |
1536 | ClientList::iterator client_it_end = clientList().end(); | ||
1551 | for (; client_it != client_it_end; ++client_it) { | 1537 | for (; client_it != client_it_end; ++client_it) { |
1552 | //TODO: Can this get stuck in a loop? | 1538 | //TODO: Can this get stuck in a loop? |
1553 | WinClient::TransientList::iterator trans_it = | 1539 | WinClient::TransientList::iterator trans_it = |
@@ -1863,9 +1849,6 @@ void FluxboxWindow::raise() { | |||
1863 | // get root window | 1849 | // get root window |
1864 | WinClient *client = getRootTransientFor(m_client); | 1850 | WinClient *client = getRootTransientFor(m_client); |
1865 | 1851 | ||
1866 | // if we don't have any root window use this as root | ||
1867 | if (client == 0) | ||
1868 | client = m_client; | ||
1869 | // if we have transient_for then we should put ourself last in | 1852 | // if we have transient_for then we should put ourself last in |
1870 | // transients list so we get raised last and thus gets above the other transients | 1853 | // transients list so we get raised last and thus gets above the other transients |
1871 | if (m_client->transientFor() && m_client != m_client->transientFor()->transientList().back()) { | 1854 | if (m_client->transientFor() && m_client != m_client->transientFor()->transientList().back()) { |
@@ -1894,10 +1877,6 @@ void FluxboxWindow::lower() { | |||
1894 | // get root window | 1877 | // get root window |
1895 | WinClient *client = getRootTransientFor(m_client); | 1878 | WinClient *client = getRootTransientFor(m_client); |
1896 | 1879 | ||
1897 | // if we don't have any root window use this as root | ||
1898 | if (client == 0) | ||
1899 | client = m_client; | ||
1900 | |||
1901 | if (client->fbwindow()) | 1880 | if (client->fbwindow()) |
1902 | lowerFluxboxWindow(*client->fbwindow()); | 1881 | lowerFluxboxWindow(*client->fbwindow()); |
1903 | } | 1882 | } |
@@ -1944,10 +1923,6 @@ void FluxboxWindow::moveToLayer(int layernum, bool force) { | |||
1944 | // get root window | 1923 | // get root window |
1945 | WinClient *client = getRootTransientFor(m_client); | 1924 | WinClient *client = getRootTransientFor(m_client); |
1946 | 1925 | ||
1947 | // if we don't have any root window use this as root | ||
1948 | if (client == 0) | ||
1949 | client = m_client; | ||
1950 | |||
1951 | FluxboxWindow *win = client->fbwindow(); | 1926 | FluxboxWindow *win = client->fbwindow(); |
1952 | if (!win) return; | 1927 | if (!win) return; |
1953 | 1928 | ||
@@ -2094,10 +2069,12 @@ void FluxboxWindow::setState(unsigned long new_state, bool setting_up) { | |||
2094 | ClientList::iterator it = clientList().begin(); | 2069 | ClientList::iterator it = clientList().begin(); |
2095 | ClientList::iterator it_end = clientList().end(); | 2070 | ClientList::iterator it_end = clientList().end(); |
2096 | for (; it != it_end; ++it) { | 2071 | for (; it != it_end; ++it) { |
2072 | (*it)->setEventMask(NoEventMask); | ||
2097 | if (new_state == IconicState) | 2073 | if (new_state == IconicState) |
2098 | (*it)->hide(); | 2074 | (*it)->hide(); |
2099 | else if (new_state == NormalState) | 2075 | else if (new_state == NormalState) |
2100 | (*it)->show(); | 2076 | (*it)->show(); |
2077 | (*it)->setEventMask(PropertyChangeMask | StructureNotifyMask | FocusChangeMask | KeyPressMask); | ||
2101 | } | 2078 | } |
2102 | 2079 | ||
2103 | saveBlackboxAttribs(); | 2080 | saveBlackboxAttribs(); |
@@ -2376,7 +2353,7 @@ void FluxboxWindow::mapNotifyEvent(XMapEvent &ne) { | |||
2376 | setState(NormalState, false); | 2353 | setState(NormalState, false); |
2377 | 2354 | ||
2378 | // we use m_focused as a signal that this should be focused when mapped | 2355 | // we use m_focused as a signal that this should be focused when mapped |
2379 | if (isFocused()) { | 2356 | if (m_focused) { |
2380 | m_focused = false; | 2357 | m_focused = false; |
2381 | focus(); | 2358 | focus(); |
2382 | } | 2359 | } |
@@ -2397,11 +2374,7 @@ void FluxboxWindow::unmapNotifyEvent(XUnmapEvent &ue) { | |||
2397 | cerr<<__FILE__<<"("<<__FUNCTION__<<"): title="<<client->title()<<endl; | 2374 | cerr<<__FILE__<<"("<<__FUNCTION__<<"): title="<<client->title()<<endl; |
2398 | #endif // DEBUG | 2375 | #endif // DEBUG |
2399 | 2376 | ||
2400 | // if window was in IconicState, then this event could have come from us | 2377 | restore(client, false); |
2401 | // unmapping the window -- but if send_event is set, then the client wants | ||
2402 | // to be withdrawn | ||
2403 | if (m_current_state == NormalState || ue.send_event) | ||
2404 | restore(client, false); | ||
2405 | 2378 | ||
2406 | } | 2379 | } |
2407 | 2380 | ||
@@ -2602,6 +2575,41 @@ void FluxboxWindow::configureRequestEvent(XConfigureRequestEvent &cr) { | |||
2602 | 2575 | ||
2603 | } | 2576 | } |
2604 | 2577 | ||
2578 | // keep track of last keypress in window, so we can decide not to focusNew | ||
2579 | void FluxboxWindow::keyPressEvent(XKeyEvent &ke) { | ||
2580 | // if there's a modifier key down, the user probably expects the new window | ||
2581 | if (FbTk::KeyUtil::instance().cleanMods(ke.state)) | ||
2582 | return; | ||
2583 | |||
2584 | // we need to ignore modifier keys themselves, too | ||
2585 | KeySym ks; | ||
2586 | char keychar[1]; | ||
2587 | XLookupString(&ke, keychar, 1, &ks, 0); | ||
2588 | if (IsModifierKey(ks)) | ||
2589 | return; | ||
2590 | |||
2591 | // if the key was return/enter, the user probably expects the window | ||
2592 | // e.g., typed the command in a terminal | ||
2593 | if (ks == XK_KP_Enter || ks == XK_Return) { | ||
2594 | // we'll actually reset the time for this one | ||
2595 | m_last_keypress_time.tv_sec = 0; | ||
2596 | return; | ||
2597 | } | ||
2598 | |||
2599 | // otherwise, make a note that the user is typing | ||
2600 | gettimeofday(&m_last_keypress_time, 0); | ||
2601 | } | ||
2602 | |||
2603 | bool FluxboxWindow::isTyping() { | ||
2604 | timeval now; | ||
2605 | if (gettimeofday(&now, NULL) == -1) | ||
2606 | return false; | ||
2607 | |||
2608 | unsigned int diff = 1000*(now.tv_sec - m_last_keypress_time.tv_sec); | ||
2609 | diff += (now.tv_usec - m_last_keypress_time.tv_usec)/1000; | ||
2610 | |||
2611 | return (diff < screen().noFocusWhileTypingDelay()); | ||
2612 | } | ||
2605 | 2613 | ||
2606 | void FluxboxWindow::buttonPressEvent(XButtonEvent &be) { | 2614 | void FluxboxWindow::buttonPressEvent(XButtonEvent &be) { |
2607 | m_last_button_x = be.x_root; | 2615 | m_last_button_x = be.x_root; |
diff --git a/src/Window.hh b/src/Window.hh index c2f36c1..82a5f3f 100644 --- a/src/Window.hh +++ b/src/Window.hh | |||
@@ -38,6 +38,7 @@ | |||
38 | #include <X11/Xlib.h> | 38 | #include <X11/Xlib.h> |
39 | #include <X11/Xutil.h> | 39 | #include <X11/Xutil.h> |
40 | 40 | ||
41 | #include <sys/time.h> | ||
41 | #include <vector> | 42 | #include <vector> |
42 | #include <string> | 43 | #include <string> |
43 | #include <memory> | 44 | #include <memory> |
@@ -337,6 +338,7 @@ public: | |||
337 | */ | 338 | */ |
338 | //@{ | 339 | //@{ |
339 | void handleEvent(XEvent &event); | 340 | void handleEvent(XEvent &event); |
341 | void keyPressEvent(XKeyEvent &ke); | ||
340 | void buttonPressEvent(XButtonEvent &be); | 342 | void buttonPressEvent(XButtonEvent &be); |
341 | void buttonReleaseEvent(XButtonEvent &be); | 343 | void buttonReleaseEvent(XButtonEvent &be); |
342 | void motionNotifyEvent(XMotionEvent &me); | 344 | void motionNotifyEvent(XMotionEvent &me); |
@@ -419,6 +421,8 @@ public: | |||
419 | inline WinClient &winClient() { return *m_client; } | 421 | inline WinClient &winClient() { return *m_client; } |
420 | inline const WinClient &winClient() const { return *m_client; } | 422 | inline const WinClient &winClient() const { return *m_client; } |
421 | 423 | ||
424 | bool isTyping(); | ||
425 | |||
422 | inline const FbTk::XLayerItem &layerItem() const { return m_frame.layerItem(); } | 426 | inline const FbTk::XLayerItem &layerItem() const { return m_frame.layerItem(); } |
423 | inline FbTk::XLayerItem &layerItem() { return m_frame.layerItem(); } | 427 | inline FbTk::XLayerItem &layerItem() { return m_frame.layerItem(); } |
424 | 428 | ||
@@ -572,6 +576,8 @@ private: | |||
572 | int m_last_move_x, m_last_move_y; // handles last pos for non opaque moving | 576 | int m_last_move_x, m_last_move_y; // handles last pos for non opaque moving |
573 | unsigned int m_last_resize_h, m_last_resize_w; // handles height/width for resize "window" | 577 | unsigned int m_last_resize_h, m_last_resize_w; // handles height/width for resize "window" |
574 | 578 | ||
579 | timeval m_last_keypress_time; | ||
580 | |||
575 | unsigned int m_workspace_number; | 581 | unsigned int m_workspace_number; |
576 | unsigned long m_current_state; // NormalState | IconicState | Withdrawn | 582 | unsigned long m_current_state; // NormalState | IconicState | Withdrawn |
577 | 583 | ||