Merge lp:~azzar1/compiz/fix-960652 into lp:compiz/0.9.8

Proposed by Andrea Azzarone
Status: Merged
Approved by: Daniel van Vugt
Approved revision: 3300
Merged at revision: 3305
Proposed branch: lp:~azzar1/compiz/fix-960652
Merge into: lp:compiz/0.9.8
Diff against target: 100 lines (+24/-9)
1 file modified
src/event.cpp (+24/-9)
To merge this branch: bzr merge lp:~azzar1/compiz/fix-960652
Reviewer Review Type Date Requested Status
Daniel van Vugt Approve
Review via email: mp+117933@code.launchpad.net

Commit message

Always call terminate callbacks for key bindings. ATM we call just the first
callback. (LP: #960652)

To post a comment you must log in.
Revision history for this message
Sam Spilsbury (smspillaz) wrote :

This looks correct, as we discussed. You can probably change statements like

> 19 + handled |= match && eventManager.triggerRelease (action, state, arguments);

changed to

bool success = false;

if (match)
    success = eventManager.triggerRelease (action, state, arguments);

handled |= success;

(|= with bool is safe AIUI)

Are you planning to add any tests for this? Preferably not manual?

Revision history for this message
Daniel van Vugt (vanvugt) wrote :

Using a bool in a bitwise expression may work, but is ugly practice. I think "bool" is a semi-opaque type. So its bitwise representation is unknown (other than it is probably != 0). I could be wrong (haven't looked at the C++ spec).

In the very least, bool in a bitwise expression will generate cppcheck warnings (http://sourceforge.net/apps/mediawiki/cppcheck/index.php?title=Main_Page#Other).

Revision history for this message
Daniel van Vugt (vanvugt) wrote :

Hmm, the spec says it's OK, kind of... 0 is always converted to false, !=0 always true. true is always converted to 1 and false is always converted to 0. By doing "handled |= x" you're asking x to be converted from a bool to int, handled to be converted from a bool to an int, and the resulting int to be converted back to a bool and stored in handled.

The spec allows this, but it is ugly.

Revision history for this message
Daniel van Vugt (vanvugt) wrote :

I can't see any problems. And the fix itself is much simpler and more benign than I initially imagined it would be. I also can't find any regressions in playing with it.

This region of code is very fragile, so any automated tests would have to be external (not modifying code).

I'm happy to ignore the bool/int conversions for now, since the spec does at least allow for it. But not recommended in future.

review: Approve
Revision history for this message
Sam Spilsbury (smspillaz) wrote :

> This region of code is very fragile, so any automated tests would have to be external (not modifying code).

I would really prefer it if we did not use this as our reason for bypassing the "you touch it, you test it" policy.

Its possible to safely modify code to get it in a test harness. See the methods used in Feathers' Working with Legacy Code[1]. If people don't have that book, I would highly recommend that they talk to their line manager and expense it and read it.

In this instance, I don't see getting this code into a test harness as that difficult. For example, if you did sprout method here on the KeyRelease handler:

bool
triggerAllReleaseEvents (unsigned int eventMods,
                         unsigned int eventKeyCode,
                         ModifierHandler *modHandler,
                         CompOption::Vector &pptions,
                         CompOption::Vector &arguments,
                         compiz::private_screen::EventManager &eventManager)

{
 state = CompAction::StateTermKey;
 bool handled = false;

 foreach (CompOption &option, options)
 {
     if (isBound (option, CompAction::BindingTypeKey, state, &action))
     {
  bindMods = modHandler->virtualToRealModMask (
      action->key ().modifiers ());
  unsigned int modKey =
      modHandler->keycodeToModifiers (eventKeycode);

  if ((event->mods && ((eventMods & modMask) != bindMods)) ||
      (!event->mods && (modKey == bindMods)))
  {
      handled |= eventManager.triggerRelease (action, state, arguments);
  }
     }
 }

 if (handled)
     return true;
        return false;
}

And then it would be pretty easy to write a test method for whether or not triggerAllReleaseEvents
a) actually triggered all events and
b) set the handled flag and causes the caller to return true;

Please spend some time considering how to test code when modifying it. Not only will you get the code under test, but you'll actually make the code better in the meantime, and you save headache for everyone else.

[1] http://www.amazon.com/Working-Effectively-Legacy-Michael-Feathers/dp/0131177052

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/event.cpp'
2--- src/event.cpp 2012-06-24 09:00:27 +0000
3+++ src/event.cpp 2012-08-02 15:53:41 +0000
4@@ -360,6 +360,8 @@
5 if (!xkbEvent.get() && !mods)
6 return false;
7
8+ bool handled = false;
9+
10 foreach (CompOption &option, options)
11 {
12 if (isBound (option, CompAction::BindingTypeKey, state, &action))
13@@ -373,12 +375,11 @@
14 else if (!xkbEvent.get() && ((mods & modMask & bindMods) != bindMods))
15 match = true;
16
17- if (match && eventManager.triggerRelease (action, state, arguments))
18- return true;
19+ handled |= match && eventManager.triggerRelease (action, state, arguments);
20 }
21 }
22
23- return false;
24+ return handled;
25 }
26
27 bool
28@@ -417,6 +418,7 @@
29 else if (event->event_type == KeyRelease)
30 {
31 state = CompAction::StateTermKey;
32+ bool handled = false;
33
34 foreach (CompOption &option, options)
35 {
36@@ -430,11 +432,13 @@
37 if ((event->mods && ((event->mods & modMask) != bindMods)) ||
38 (!event->mods && (modKey == bindMods)))
39 {
40- if (eventManager.triggerRelease (action, state, arguments))
41- return true;
42+ handled |= eventManager.triggerRelease (action, state, arguments);
43 }
44 }
45 }
46+
47+ if (handled)
48+ return true;
49 }
50
51 return false;
52@@ -757,6 +761,7 @@
53 }
54 break;
55 case KeyRelease:
56+ {
57 o[0].value ().set ((int) event->xkey.window);
58 o[1].value ().set ((int) orphanData.activeWindow);
59 o[2].value ().set ((int) event->xkey.state);
60@@ -770,13 +775,19 @@
61 o[6].value ().set ((int) event->xkey.keycode);
62 o[7].value ().set ((int) event->xkey.time);
63
64+ bool handled = false;
65+
66 foreach (CompPlugin *p, CompPlugin::getPlugins ())
67 {
68 CompOption::Vector &options = p->vTable->getOptions ();
69- if (triggerKeyReleaseBindings (options, &event->xkey, o))
70- return true;
71+ handled |= triggerKeyReleaseBindings (options, &event->xkey, o);
72 }
73+
74+ if (handled)
75+ return true;
76+
77 break;
78+ }
79 case EnterNotify:
80 if (event->xcrossing.mode != NotifyGrab &&
81 event->xcrossing.mode != NotifyUngrab &&
82@@ -977,12 +988,16 @@
83 if (stateEvent->event_type == KeyPress)
84 eventManager.resetPossibleTap();
85
86+ bool handled = false;
87+
88 foreach (CompPlugin *p, CompPlugin::getPlugins ())
89 {
90 CompOption::Vector &options = p->vTable->getOptions ();
91- if (triggerStateNotifyBindings (options, stateEvent, arg))
92- return true;
93+ handled |= triggerStateNotifyBindings (options, stateEvent, arg);
94 }
95+
96+ if (handled)
97+ return true;
98 }
99 else if (xkbEvent->xkb_type == XkbBellNotify)
100 {

Subscribers

People subscribed via source and target branches