Click here to Skip to main content
15,879,096 members
Articles / Programming Languages / C++

Calendar Gadget Using Qt Framework

Rate me:
Please Sign up or sign in to vote.
3.93/5 (11 votes)
14 Jan 2011LGPL34 min read 60.5K   3.9K   28   10
A very simple calendar to be displayed on your desktop similar to a Vista or Windows 7 gadget, but also works for Windows XP.

CalendarGadget/CalendarGadget.png

Introduction

The application is realized using the Qt framework. Qt provides you with all the functionality needed to develop advanced GUI applications on desktop and embedded platforms. Qt uses the native graphics APIs of each platform it supports, taking full advantage of system resources and ensuring that applications have the native look and feel. Using Qt is very easy and intuitive and, in my opinion, is the next best thing after Microsoft .NET Framework for Windows based applications. It has the advantage that the same code can be compiled for many platforms (Windows, Linux, Mac OS), is written entirely in C++ (some projects may require only C++), and is free (you can choose from LGPL/GPL/Commercial license).

Background

While working, I find it very useful to have a calendar at hand. I have tried to use some existing applications, but none could display the calendar week number. So I decided to have my own calendar gadget. The idea was to be able to use my gadget also on Windows XP. If you want to start the program together with Windows, just create a shortcut to your Startup folder.

Using the Code

In order to compile the code, you need to have the Qt framework and the Qt Visual Studio Add-in (in case you compile using Visual Studio). You can download them from http://qt.nokia.com. Visual Studio 2008 or QtCreator 2.0.1 can be used to compile the code.

The Qt framework is compiled without SSL support. This is required in order to establish a Google connection and to get the authentication code for the calendar service. OpenSLL is the best choice since it is free. You can get a precompiled version from http://www.openssl.org/related/binaries.html.

To make the application installer, I used InnoSetup. This is an Open Source project used for creating Windows installers. You can download this from http://www.jrsoftware.org/isinfo.php.

Points of Interest

The Gadget class offers the basic functionality of a gadget: a nice frame, some fade in/out animation, and the most important feature is that it keeps the window on the desktop when you choose “Show desktop”.

Normally, when the user chooses to show the desktop, all windows are hidden. Unfortunately, there is no flag or style to avoid this behavior, and after a few hours of documentation on the net, I found the way to do this. All that is required is to have a global event hook by providing a callback function.

Keep the ID for each object.

C++
HWINEVENTHOOK globalHookId;  

Create the event hook when the actual window is shown.

C++
globalHookId = SetWinEventHook(EVENT_SYSTEM_FOREGROUND, 
               EVENT_SYSTEM_FOREGROUND, NULL, 
               (WINEVENTPROC)HandleWinEvent,0,0,0); 

Remove the event hook from the system when the object is no longer required (in the destructor).

C++
UnhookWinEvent(globalHookId); 

HandleWinEvent is a global function that will loop through all the existing gadgets on the desktop and show them.

C++
void CALLBACK HandleWinEvent(HWINEVENTHOOK hook, DWORD event, HWND hwnd, 
                             LONG idObject, LONG idChild, DWORD dwEventThread, 
                             DWORD dwmsEventTime) 
{
    if (event == EVENT_SYSTEM_FOREGROUND) 
    {
        TCHAR tmp[255];
        int r = GetClassName(hwnd, tmp, 250);
        if (wcscmp(tmp, L"WorkerW")==0) 
        {
            Gadget::assureVisibility();
        }
    }
}

The CalendarService class is used to get all-day-events from your Google Calendar using the Google Calendar API. This is done in three steps: obtain an authentication code using the user name and password, get a session ID, query the calendar for events:

  1. For the authentication, a post needs to be set to "https://www.google.com/accounts/ClientLogin", and in return, the auth code will be received. This is kept and used for all other requests. The authentication part is done in AuthService. Details about the login can be read on http://code.google.com/intl/en/apis/gdata/docs/auth/overview.html#ClientLogin.
  2. For the authentication, a post needs to be set to "https://www.google.com/accounts/ClientLogin", and in return, the auth code will be received. This is kept and used for all other requests. The authentication part is done in AuthService.
  3. Trying to get the data directly will not work because all requests will redirected. Because of this, a get request must be performed at "http://www.google.com/calendar/feeds/default/private/full" using "X-If-No-Redirect" set to "1" in order to get a session ID. "X-Redirect-Location" will be read from the reply. Details about the Calendar API can be read on http://code.google.com/intl/en/apis/calendar/data/2.0/reference.html.
  4. C++
    QNetworkRequest request = QNetworkRequest();
    ...
    request.setRawHeader("X-If-No-Redirect", "1");
  5. In order to limit the results, a query is made using a start time and an end time. The start and end are the values represented by the first and last date shown in the calendar.
  6. C++
    QUrl address("http://www.google.com/calendar/feeds/default/private/full");
    
    address.addQueryItem("gsessionid", session);
    address.addQueryItem("start-min", 
      QString("%1T00:00:00").arg(newStartDate.toString("yyyy-MM-dd")));
    address.addQueryItem("start-max", 
      QString("%1T23:59:59").arg(newEndDate.toString("yyyy-MM-dd")));

I wanted to start the application together with Windows so the password is also saved in the application settings. I did not want to save the password in plain text, so I used the Windows Crypto API to do a simple RC4 encryption. This is by no means safe, but it protects my password from simple view. Here is the basic workflow (check out the full implementation in the Settings class):

C++
// get a CSP handle
HCRYPTPROV CryptoProv = NULL;
if( !CryptAcquireContext(&CryptoProv, NULL, NULL, PROV_RSA_FULL, 0))
  if (!CryptAcquireContext(&CryptoProv, NULL, NULL, 
                           PROV_RSA_FULL, CRYPT_NEWKEYSET))
    if (!CryptAcquireContext(&CryptoProv, NULL, NULL, 
                             PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
      return "";

// import do-nothing exponent-of-one keypair
HCRYPTKEY ExponentOfOneKey = NULL;
CryptImportKey(CryptoProv, PrivateKeyWithExponentOfOne, 
               sizeof(PrivateKeyWithExponentOfOne), 0, 0, &ExponentOfOneKey);

// import known key from RC4 template
HCRYPTKEY RC4Key = NULL;
DWORD cbBlob = sizeof(RC4KeyBlock);
CryptImportKey(CryptoProv, RC4KeyBlock, cbBlob, ExponentOfOneKey, 0, &RC4Key);

// encrypt the data
CryptEncrypt( RC4Key, 0, 1, 0, data, &length, length);

// clean up
CryptDestroyKey(RC4Key);
CryptDestroyKey(ExponentOfOneKey);
CryptReleaseContext(CryptoProv,0);

History

  • Version 1.0.1
    • Initial version
  • Version 1.0.2
    • Gadget windows stay on top after "Show desktop"
  • Version 1.0.3
    • Fixed email link in about
  • Version 1.0.4
    • Calendar Gadget - rename
  • Version 1.0.5
    • Show all day events from Google Calendar
  • Version 1.0.6
    • Upgraded to Qt 4.7.0
    • ConnectDialog refactored
    • Button refactored using the state machine mechanism
    • Password remembered in Settings.ini
    • Setup added
  • Version 1.0.7
    • HTTP replaced with QNetworkManager
    • Proxy
    • Animations added
    • Code comments

License

This article, along with any associated source code and files, is licensed under The GNU Lesser General Public License (LGPLv3)


Written By
Software Developer
Germany Germany
My programming experience starts from 1998 in High School. I have graduated “Politehnica” University of Timisoara and worked as a developer since 2005. Currently I work as a C/C++ developer in the automotive business.
I’m interested in windows/linux based development using different technologies(.Net, MFC, Qt) and signal processing algorithms.

Comments and Discussions

 
QuestionCompiled version against QT 5.3.1 Pin
Member 1098067811-Aug-14 0:21
Member 1098067811-Aug-14 0:21 
GeneralMy vote of 5 Pin
JG3318-Mar-13 10:11
JG3318-Mar-13 10:11 
QuestionHow to connect Google? [modified] Pin
vudvpro1-Apr-11 23:41
vudvpro1-Apr-11 23:41 
GeneralCast problem in SetWinEventHook Pin
gzorg22-Dec-10 22:08
gzorg22-Dec-10 22:08 
Generaldoes not work on windows 7 (64-bit) Pin
luckmiky26-Jun-10 5:52
luckmiky26-Jun-10 5:52 
GeneralRe: does not work on windows 7 (64-bit) Pin
BD Mihai3-Jul-10 11:56
BD Mihai3-Jul-10 11:56 
This is strange... The application is working on Windows 7 (64 bit) which I have installed.
What seems to be the problem? It is not starting at all?
GeneralRe: does not work on windows 7 (64-bit) Pin
luckmiky8-Jul-10 7:30
luckmiky8-Jul-10 7:30 
GeneralCool Pin
Fredrik Bornander16-Mar-10 2:54
professionalFredrik Bornander16-Mar-10 2:54 
GeneralWhy not do it with free software: QtCreator Pin
Wolfgang_Baron15-Mar-10 13:35
professionalWolfgang_Baron15-Mar-10 13:35 
GeneralNice, but I think you should explain a bit more. Pin
CPallini14-Mar-10 22:55
mveCPallini14-Mar-10 22:55 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.