~ubuntu-branches/ubuntu/raring/workrave/raring

« back to all changes in this revision

Viewing changes to backend/src/win32/W32LowLevelMonitor.cc

  • Committer: Package Import Robot
  • Author(s): Francois Marier, Francois Marier, Jordi Mallach
  • Date: 2012-05-28 11:29:40 UTC
  • mfrom: (1.2.9)
  • Revision ID: package-import@ubuntu.com-20120528112940-bbbsjkk30fom9s8x
Tags: 1.9.909+abc941eb70-1
[ Francois Marier ]
* New upstream snapshot
  - Drop leak-fix patch (applied upstream)
  - Document how the tarball is built in README.source
* Build GNOME applets and use gsettings
* Massive update of Build-Depends as per configure.ac

* Update README.source with snapshot instructions
* Switch to machine-readable copyright file
* Update alioth git repo links
* Bump debhelper version to 9
* Bump Standards-Version to 3.9.3

[ Jordi Mallach ]
* Avoid references to GNU/Linux in manpage.
* Drop build dependency on libgnet-dev, it's obsolete and unneeded.
* Add myself to Uploaders.
* Rewrite d/rules into dh style.
  - Move all install tweaks to .install files.
  - Install manpages using dh_installman.
* As a side effect, the package installs arch-dependant data in the
  arch triplet directory; add the required Pre-Depends for m-a-support.
* Bring back GNOME Panel applet (for GNOME 3 fallback mode) and ship the
  new GNOME Shell extension (closes: #642514, #666100).
* Add private_dirs.patch: move libworkrave-private and GObject
  Introspection files to a private dir, so they are really out of the
  way, but disable it for now as it breaks the Shell extension.
* Move typelib out of the triplet dir as gobject-introspection is not
  M-A ready yet.
* Enable dh_autoreconf for the above patches.
* Add lintian overrides.
* Add necessary Breaks/Replaces as the xpm icon has moved to workrave-data.
* Prefix all debhelper files with package name.
* Suggest gnome-shell and gnome-panel.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
// W32LowLevelMonitor.cc --- ActivityMonitor for W32
2
2
//
3
 
// Copyright (C) 2007, 2010 Ray Satiro <raysatiro@yahoo.com>
 
3
// Copyright (C) 2007, 2010, 2012 Ray Satiro <raysatiro@yahoo.com>
4
4
// All rights reserved.
5
5
//
6
6
// This program is free software; you can redistribute it and/or modify
20
20
--
21
21
From MSDN, re WH_KEYBOARD_LL & WH_MOUSE_LL:
22
22
 
23
 
This hook is called in the context of the thread that 
24
 
installed it. The call is made by sending a message to 
25
 
the thread that installed the hook. 
 
23
This hook is called in the context of the thread that
 
24
installed it. The call is made by sending a message to
 
25
the thread that installed the hook.
26
26
 
27
 
Therefore, the thread that installed the hook must 
28
 
have a message loop. 
 
27
Therefore, the thread that installed the hook must
 
28
have a message loop.
29
29
--
30
30
 
31
 
Because a low-level hook is called in the context of 
32
 
the thread that installed it, we can install the hook 
 
31
Because a low-level hook is called in the context of
 
32
the thread that installed it, we can install the hook
33
33
from a time critical thread, and run a message loop.
34
34
 
35
35
This should solve the Philips slowdown problem:
36
 
1. high priority callback thread returns immediately after 
 
36
1. high priority callback thread returns immediately after
37
37
posting a message to the dispatch thread
38
38
2. the dispatch thread processes and notifies main thread
39
39
 
78
78
Therefore BOOL functions can return -1.
79
79
MSDN notes GetMessage BOOL return is not only 0,1 but also -1.
80
80
*/
81
 
BOOL ( WINAPI *W32LowLevelMonitor::GetMessageW ) 
82
 
    ( LPMSG, HWND, UINT, UINT ) = NULL;
83
 
BOOL ( WINAPI *W32LowLevelMonitor::PeekMessageW )
84
 
    ( LPMSG, HWND, UINT, UINT, UINT ) = NULL;
85
 
BOOL ( WINAPI *W32LowLevelMonitor::PostThreadMessageW )
86
 
    ( DWORD, UINT, WPARAM, LPARAM ) = NULL;
87
 
HHOOK ( WINAPI *W32LowLevelMonitor::SetWindowsHookExW )
88
 
    ( int, HOOKPROC, HINSTANCE, DWORD ) = NULL;
89
 
BOOL ( WINAPI *W32LowLevelMonitor::SwitchToThread ) ( void ) = NULL;
90
81
 
91
82
 
92
83
W32LowLevelMonitor::W32LowLevelMonitor()
93
84
{
94
85
  TRACE_ENTER( "W32LowLevelMonitor::W32LowLevelMonitor" );
95
 
  
 
86
 
96
87
  if( singleton != NULL )
97
88
    {
98
89
      TRACE_RETURN( " singleton != NULL " );
99
90
      return;
100
91
    }
101
 
  
 
92
 
102
93
  singleton = this;
103
 
  
 
94
 
104
95
  dispatch = new thread_struct;
105
96
  dispatch->name = "Dispatch";
106
 
  
 
97
 
107
98
  callback = new thread_struct;
108
99
  callback->name = "Callback";
109
 
  
 
100
 
110
101
  k_hook = NULL;
111
102
  m_hook = NULL;
112
 
  
 
103
 
 
104
  process_handle = GetModuleHandle( NULL );
 
105
 
113
106
  TRACE_EXIT();
114
107
}
115
108
 
117
110
W32LowLevelMonitor::~W32LowLevelMonitor()
118
111
{
119
112
  TRACE_ENTER( "W32LowLevelMonitor::~W32LowLevelMonitor" );
120
 
  
 
113
 
121
114
  if( singleton != this )
122
115
    {
123
116
      TRACE_RETURN( " singleton != this " );
124
117
      return;
125
118
    }
126
 
  
 
119
 
127
120
  terminate();
128
 
  
 
121
 
129
122
  delete dispatch;
130
123
  delete callback;
131
 
  
 
124
 
132
125
  dispatch = NULL;
133
126
  callback = NULL;
134
127
  singleton = NULL;
135
 
  
 
128
 
136
129
  TRACE_EXIT();
137
130
}
138
131
 
139
132
 
140
 
bool W32LowLevelMonitor::check_api()
141
 
{
142
 
  TRACE_ENTER( "W32LowLevelMonitor::check_api" );
143
 
  
144
 
  process_handle = GetModuleHandle( NULL );
145
 
  HMODULE user32_handle = GetModuleHandleA( "user32.dll" );
146
 
  
147
 
  GetMessageW = ( BOOL ( WINAPI * ) ( LPMSG, HWND, UINT, UINT ) )
148
 
      GetProcAddress( user32_handle, "GetMessageW" );
149
 
  
150
 
  PeekMessageW = ( BOOL ( WINAPI * ) ( LPMSG, HWND, UINT, UINT, UINT ) )
151
 
      GetProcAddress( user32_handle, "PeekMessageW" );
152
 
  
153
 
  PostThreadMessageW = ( BOOL ( WINAPI * ) ( DWORD, UINT, WPARAM, LPARAM ) )
154
 
      GetProcAddress( user32_handle, "PostThreadMessageW" );
155
 
  
156
 
  SetWindowsHookExW = ( HHOOK ( WINAPI * ) ( int, HOOKPROC, HINSTANCE, DWORD ) )
157
 
      GetProcAddress( user32_handle, "SetWindowsHookExW" );
158
 
  
159
 
  SwitchToThread = ( BOOL ( WINAPI * ) ( void ) )
160
 
      GetProcAddress( GetModuleHandleA( "kernel32.dll" ), "SwitchToThread" );
161
 
  
162
 
  if( process_handle && GetMessageW && PeekMessageW && 
163
 
      PostThreadMessageW && SetWindowsHookExW && SwitchToThread )
164
 
    {
165
 
      TRACE_EXIT();
166
 
      return true;
167
 
    }
168
 
  else
169
 
    {
170
 
      TRACE_MSG( " failed." );
171
 
      TRACE_MSG( "process_handle == " << process_handle );
172
 
      TRACE_MSG( "GetMessageW == " << GetMessageW );
173
 
      TRACE_MSG( "PeekMessageW == " << PeekMessageW );
174
 
      TRACE_MSG( "PostThreadMessageW == " << PostThreadMessageW );
175
 
      TRACE_MSG( "SetWindowsHookExW == " << SetWindowsHookExW );
176
 
      TRACE_MSG( "SwitchToThread == " << SwitchToThread );
177
 
      TRACE_EXIT();
178
 
      return false;
179
 
    }
180
 
}
181
 
 
182
 
 
183
133
bool W32LowLevelMonitor::init()
184
134
{
185
135
  TRACE_ENTER( "W32LowLevelMonitor::init" );
186
 
  
 
136
 
187
137
  if( singleton != this )
188
138
    {
189
139
      TRACE_RETURN( " singleton != this " );
190
140
      return false;
191
141
    }
192
 
  
193
 
  if( !check_api() )
194
 
    {
195
 
      TRACE_RETURN( " : init failed. " );
196
 
      return false;
197
 
    }
198
142
 
199
143
  terminate();
200
 
  
201
 
  dispatch->handle = 
 
144
 
 
145
  dispatch->handle =
202
146
      CreateThread( NULL, 0, thread_Dispatch, this, 0, &dispatch->id );
203
 
  
 
147
 
204
148
  if( !wait_for_thread_queue( dispatch ) )
205
149
    {
206
150
      terminate();
207
151
      TRACE_EXIT();
208
152
      return false;
209
153
    }
210
 
  
211
 
  callback->handle = 
 
154
 
 
155
  callback->handle =
212
156
      CreateThread( NULL, 0, thread_Callback, this, 0, &callback->id );
213
 
  
 
157
 
214
158
  if( !wait_for_thread_queue( callback ) )
215
159
    {
216
160
      terminate();
217
161
      TRACE_EXIT();
218
162
      return false;
219
163
    }
220
 
  
 
164
 
221
165
  Harpoon::init(NULL);
222
 
  
 
166
 
223
167
  TRACE_EXIT();
224
168
  return true;
225
169
}
227
171
bool W32LowLevelMonitor::wait_for_thread_queue( thread_struct *thread )
228
172
{
229
173
  TRACE_ENTER_MSG( "W32LowLevelMonitor::wait_for_thread_queue : ", thread->name);
230
 
  
 
174
 
231
175
  if( !thread->handle || !thread->id )
232
176
    {
233
177
      TRACE_RETURN( " thread: creation failed." );
234
178
      return false;
235
179
    }
236
 
  
 
180
 
237
181
  DWORD thread_exit_code;
238
 
  
 
182
 
239
183
  do
240
184
    {
241
185
      thread_exit_code = 0;
 
186
      Sleep( 1 );
242
187
      GetExitCodeThread( thread->handle, &thread_exit_code );
243
188
      if( thread_exit_code != STILL_ACTIVE )
244
189
        {
245
190
          TRACE_RETURN( " thread: terminated prematurely." );
246
191
          return false;
247
192
        }
248
 
      ( *SwitchToThread )();
249
193
    } while( thread->active == false );
250
 
  
 
194
 
251
195
  SetLastError( 0 );
252
 
  BOOL ret = ( *PostThreadMessageW )( thread->id, 0xFFFF, 0, 0 );
 
196
  BOOL ret = PostThreadMessageW( thread->id, 0xFFFF, 0, 0 );
253
197
  DWORD gle = GetLastError();
254
 
  
 
198
 
255
199
  if( !ret || gle )
256
200
    {
257
201
      TRACE_MSG( " thread: PostThreadMessage test failed." );
270
214
{
271
215
  if( singleton != this )
272
216
      return;
273
 
  
 
217
 
274
218
  unhook();
275
 
  
 
219
 
276
220
  terminate_thread( callback );
277
221
  terminate_thread( dispatch );
278
222
 
283
227
void W32LowLevelMonitor::terminate_thread( thread_struct *thread )
284
228
{
285
229
  thread->active = false;
286
 
  
 
230
 
287
231
  if( thread->id )
288
 
      ( *PostThreadMessageW )( thread->id, WM_QUIT, 0, 0 );
289
 
  
 
232
      PostThreadMessageW( thread->id, WM_QUIT, 0, 0 );
 
233
 
290
234
  wait_for_thread_to_exit( thread );
291
 
  
 
235
 
292
236
  if( thread->handle != NULL )
293
237
    {
294
238
      CloseHandle( thread->handle );
301
245
void W32LowLevelMonitor::wait_for_thread_to_exit( thread_struct *thread )
302
246
{
303
247
  DWORD thread_exit_code = 0;
 
248
 
 
249
  if( !thread || !thread->handle )
 
250
    return;
304
251
  
305
 
  do 
 
252
  do
306
253
    {
307
 
      ( *SwitchToThread )();
 
254
      Sleep( 1 );
308
255
      GetExitCodeThread( thread->handle, &thread_exit_code );
309
256
    } while( thread_exit_code == STILL_ACTIVE );
310
257
}
312
259
 
313
260
void W32LowLevelMonitor::unhook()
314
261
{
315
 
  UnhookWindowsHookEx( k_hook );
316
 
  k_hook = NULL;
317
 
  
318
 
  UnhookWindowsHookEx( m_hook );
319
 
  m_hook = NULL;
 
262
  if( k_hook )
 
263
  {
 
264
    UnhookWindowsHookEx( k_hook );
 
265
    k_hook = NULL;
 
266
  }
 
267
 
 
268
  if( m_hook )
 
269
  {
 
270
    UnhookWindowsHookEx( m_hook );
 
271
    m_hook = NULL;
 
272
  }
320
273
}
321
274
 
322
275
 
330
283
DWORD W32LowLevelMonitor::dispatch_thread()
331
284
{
332
285
  dispatch->active = false;
333
 
  
 
286
 
334
287
  bool ret = 0;
335
288
  MSG msg;
336
 
  
337
 
  // It's good practice to force creation of the thread 
 
289
 
 
290
  // It's good practice to force creation of the thread
338
291
  // message queue before setting active.
339
 
  ( *PeekMessageW )( &msg, NULL, WM_USER, WM_USER, PM_NOREMOVE );
 
292
  PeekMessageW( &msg, NULL, WM_USER, WM_USER, PM_NOREMOVE );
340
293
  dispatch->active = true;
341
 
  
342
 
  while( ret = ( *GetMessageW )( &msg, NULL, 0, 0 ) > 0  && dispatch->active )
 
294
 
 
295
  while( ( ret = GetMessageW( &msg, NULL, 0, 0 ) > 0 ) && dispatch->active )
343
296
    {
344
297
      msg.message &= 0xFFFF;
345
298
      if( msg.message > WM_APP)
352
305
              case WM_MOUSEMOVE:
353
306
                  fire_mouse( msg.wParam, msg.lParam, 0 );
354
307
                  break;
355
 
              
 
308
 
356
309
              case WM_MOUSEWHEEL:
357
310
              case WM_MOUSEHWHEEL:
358
311
                  fire_mouse( msg.wParam, msg.lParam, 1 );
359
312
                  break;
360
 
              
 
313
 
361
314
              case WM_LBUTTONDOWN:
362
315
              case WM_MBUTTONDOWN:
363
316
              case WM_RBUTTONDOWN:
364
317
              case WM_XBUTTONDOWN:
365
318
                  fire_button( true );
366
319
                  break;
367
 
              
 
320
 
368
321
              case WM_LBUTTONUP:
369
322
              case WM_MBUTTONUP:
370
323
              case WM_RBUTTONUP:
385
338
              fire_action();
386
339
        }
387
340
    }
388
 
  
 
341
 
389
342
  dispatch->active = false;
390
 
  
 
343
 
391
344
  // Always return a value != STILL_ACTIVE (259)
392
345
  return (DWORD) ret;
393
346
}
403
356
DWORD W32LowLevelMonitor::time_critical_callback_thread()
404
357
{
405
358
  callback->active = false;
406
 
  
 
359
 
407
360
  int i = 0;
408
 
  HANDLE handle = GetCurrentThread();
409
 
  
410
 
  // An attempt to set the thread priority to 
 
361
  MSG msg;
 
362
 
 
363
  // An attempt to set the thread priority to
411
364
  // THREAD_PRIORITY_TIME_CRITICAL.
412
 
  // Try for several seconds.
413
 
  while( SetThreadPriority( handle, 15 ) == 0 )
 
365
  for( i = 0; ( !SetThreadPriority( GetCurrentThread(), 15 ) && ( i < 100 ) ); ++i )
414
366
    {
415
 
      if( ++i > 100 )
416
 
          return (DWORD) 0;
417
 
      else
418
 
      //Give up our time slice, try next schedule.
419
 
          ( *SwitchToThread )();
 
367
      Sleep( 1 );
420
368
    }
 
369
 
421
370
  /*
422
371
  Do not double check using GetThreadPriority.
423
 
  It's possible, throughout this thread's lifetime, that 
 
372
  It's possible, throughout this thread's lifetime, that
424
373
  an administrative application could change the priority.
425
374
  */
426
 
  
427
 
  /* MSDN:
428
 
  The system creates a thread's message queue when the thread 
429
 
  makes its first call to one of the User or GDI functions. 
430
 
  */
431
 
  unhook(); // thread message queue created here
432
 
  
433
 
  k_hook = 
434
 
      ( *SetWindowsHookExW )( WH_KEYBOARD_LL,  &k_hook_callback, process_handle, 0 );
435
 
  m_hook = 
436
 
      ( *SetWindowsHookExW )( WH_MOUSE_LL,  &m_hook_callback, process_handle, 0 );
437
 
  
 
375
 
 
376
  // It's good practice to force creation of the thread
 
377
  // message queue before setting active.
 
378
  PeekMessageW( &msg, NULL, WM_USER, WM_USER, PM_NOREMOVE );
 
379
 
 
380
  unhook();
 
381
 
 
382
  k_hook =
 
383
      SetWindowsHookExW( WH_KEYBOARD_LL, &k_hook_callback, process_handle, 0 );
 
384
  m_hook =
 
385
      SetWindowsHookExW( WH_MOUSE_LL, &m_hook_callback, process_handle, 0 );
 
386
 
438
387
  if( !k_hook || !m_hook )
439
388
    {
440
389
      unhook();
441
390
      return (DWORD) 0;
442
391
    }
443
 
  
444
 
  
445
 
  MSG msg;
446
 
  
447
 
  // It's good practice to force creation of the thread 
448
 
  // message queue before setting active.
449
 
  ( *PeekMessageW )( &msg, NULL, WM_USER, WM_USER, PM_NOREMOVE );
 
392
 
450
393
  callback->active = true;
451
 
  
452
 
  // Message loop. As noted, a hook is called in the 
 
394
 
 
395
  // Message loop. As noted, a hook is called in the
453
396
  // context of the thread that installed it. i.e. this one.
454
 
  while( ( *GetMessageW )( &msg, NULL, 0, 0 ) && callback->active )
 
397
  while( GetMessageW( &msg, NULL, 0, 0 ) && callback->active )
455
398
  ;
456
 
  
 
399
 
457
400
  unhook();
458
401
  callback->active = false;
459
 
  
 
402
 
460
403
  // Always return a value != STILL_ACTIVE (259)
461
404
  return (DWORD) 1;
462
405
}
463
406
 
464
407
 
465
 
LRESULT CALLBACK W32LowLevelMonitor::k_hook_callback( 
 
408
LRESULT CALLBACK W32LowLevelMonitor::k_hook_callback(
466
409
    int nCode, WPARAM wParam, LPARAM lParam )
467
410
{
468
411
  DWORD flags = ( (_KBDLLHOOKSTRUCT *) lParam )->flags;
469
 
  
 
412
 
470
413
  if( !nCode && !( flags & LLKHF_INJECTED ) )
471
414
  // If there is an event, and it's not injected, notify.
472
415
    {
473
 
      ( *PostThreadMessageW )
474
 
        ( 
 
416
      PostThreadMessageW
 
417
        (
475
418
          dispatch->id, //idThread
476
419
          WM_APP, //Msg
477
420
          (WPARAM) flags, //wParam
478
421
          (LPARAM) 0 //lParam
479
422
        );
480
423
    }
481
 
  
 
424
 
482
425
  return CallNextHookEx( (HHOOK) 0, nCode, wParam, lParam );
483
426
}
484
427
 
485
428
 
486
 
LRESULT CALLBACK W32LowLevelMonitor::m_hook_callback( 
 
429
LRESULT CALLBACK W32LowLevelMonitor::m_hook_callback(
487
430
    int nCode, WPARAM wParam, LPARAM lParam )
488
431
{
489
432
  DWORD flags = ( (_MSLLHOOKSTRUCT *) lParam )->flags;
490
 
  
 
433
 
491
434
 
492
435
  if( !nCode ) // && !( flags & LLMHF_INJECTED ) )
493
436
  // If there is an event, and it's not injected, notify.
494
437
  // RC: My Wacom tablet driver injects mouse move events...
495
438
    {
496
 
      ( *PostThreadMessageW )
 
439
      PostThreadMessageW
497
440
        (
498
441
          dispatch->id, //idThread
499
442
          WM_APP + (DWORD) wParam, //Msg
501
444
          (LPARAM) ( (_MSLLHOOKSTRUCT *) lParam )->pt.y //lParam
502
445
        );
503
446
    }
504
 
  
 
447
 
505
448
  return CallNextHookEx( (HHOOK) 0, nCode, wParam, lParam );
506
449
}
507
450