I'm looking to mess around with C++ and build some kind of desktop application that can interact with other windows. Something like a window tiling manager (e.g. minimizing current windows, snapping windows into a grid etc). Is this possible to do in C++? I've only ever worked with command line stuff, so is there a good framework for this kind of work? Anything in the right direction or how I can accomplish something like this would be awesome.
In Windows
You can use EnumWindows to iterate through each of the windows. It starts from the topmost window and works its way down. The following code will loop through each visible window and print out the winow's text.
#include <windows.h>
#include <stdio.h>
BOOL CALLBACK EnumWindowsProc(HWND hWnd, long lParam) {
char buff[255];
if (IsWindowVisible(hWnd)) {
GetWindowText(hWnd, (LPSTR) buff, 254);
printf("%s\n", buff);
}
return TRUE;
}
int main() {
EnumWindows(EnumWindowsProc, 0);
return 0;
}
Since you have the handle of each window, you can do further manipulations by sending messages to them.
I created a tool to play with windows and shapes called Desktop Playground that uses this very method.
I spawn off a thread and store each window in a hash table with their coordinates and size. Then I iterate through and compare their current position and size with their previous one and execute callbacks to let my main thread know whether a window was Created, Moved, Reiszed, or Destroyed.
On Windows you can use the SendMessage function to active windows or processes.
This question is highly related on which OS, or GUI framework is used for such application you want to create.
If the OS supports interfaces for such interaction, it certainly can be used with C++ if there's a certain language binding to the GUI control API (C/C++) provided.
Usually it's not a good idea to use these API's natively from your code, but through a C++ library that abstracts the low level bits and operations out.
At a next level there are libraries available, that even support abstractions for diverse OS specific GUI and System Control APIs. If you're looking for OS portable code, check out the Qt framework for example.
Related
I dont have a lot of experience with C so sorry if this is a dumb question.
I'm writing an application that will monitor and manipulate application windows and i need to figure out how to do the following:
Get a list of all application windows
Be notified when a window is resized
Be notified when the a user maximises/minimises a window
Set the size and position of an application window.
I spent quite a while searching google but did not find anything useful. The language is not to important as i could make this project work with C or C++ maybe even C#
Any help would be appreciated.
on linux windows are handled by X11 ( X Window System https://en.wikipedia.org/wiki/X_Window_System, https://en.wikipedia.org/wiki/X.Org_Server ) and X Window Managers like Enlightenment ( https://en.wikipedia.org/wiki/Comparison_of_X_window_managers ), and tools and libraries like xdotool or Xlib ( https://www.lemoda.net/c/xlib-resize/ ...).
X11 is low(est)-level application window handling on linux
on this X11 basis you normally write programs that contain windows using Qt or GTK+ framework, in both frameworks are implemented methods to do all your mentioned tasks ( What should I choose: GTK+ or Qt? )
important is the installed X windows manager ( https://en.wikipedia.org/wiki/Comparison_of_X_window_managers ). In the overlying Qt and GTK+ frameworks only functions can be used that are implemented by the underlying X window manager
resize window event capturing in Qt and GTK :
http://www.qtcentre.org/threads/54968-how-to-detect-window-resize-event
GTK detecting window resize from the user
A list of all open X windows can be queried with XQueryTree function from the Xlib library
( How to get the list of open windows from xserver )
xwininfo ( https://linux.die.net/man/1/xwininfo ) can be used to collect information about open windows
EDIT: I was just thinking of something else when I answered the question the first time. In fact what you are asking for is pretty simple.
Here is a potential solution.
Register for Create/Destroy/Resize window events (XCB_EVENT_MASK_STRUCTURE_NOTIFY) so you can keep up with newly added/destroyed/resized windows. Depending on your setup you may want to add the XCB_EVENT_MASK_PROPERTY_CHANGE so you can tell if the "minimized" or "maximized" property is set.
Query _NET_CLIENT_LIST (ie via xcb_ewmh_get_client_list) or use
XQueryTree to get all (application) windows. The former will give you a filtered list that will probably be a superset of "application windows". The latter will give you every single window which will probably be more than what you want.
Send configure request to resize the window. Like others have said, xdotool can be used to send these requests. Note that, in general, these requests are likely to be blocked/modified by the WM. If you don't own the window, there is no good way around this unless your WM allows it. If you do own the window, you could set the override redirect field on the window.
Below is a code sample on how you might listen for events (complied with -lxcb). Note that this is just a sample and you would probably want to filter events in the switch statement (ie you don't want all properties)
void main(){
//create connection using default display
xcb_connection_t* dis = xcb_connect(NULL, NULL);
if(xcb_connection_has_error(dis))
exit(1);
xcb_screen_t*screen=xcb_setup_roots_iterator(xcb_get_setup(dis)).data;
int root = screen->root;
int mask = XCB_EVENT_MASK_STRUCTURE_NOTIFY|XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY|XCB_EVENT_MASK_PROPERTY_CHANGE;
if(xcb_request_check(dis,xcb_change_window_attributes_checked(dis, root,XCB_CW_EVENT_MASK, &mask)))
exit(1);//an error occured
while(1){
xcb_generic_event_t *event;
event = xcb_wait_for_event(dis);
switch(event->response_type){
case XCB_CREATE_NOTIFY:
printf("New window\n");
break;
case XCB_DESTROY_NOTIFY:
printf("Window deleted\n");
break;
case XCB_PROPERTY_NOTIFY:
printf("Window property change\n");
break;
case XCB_CONFIGURE_NOTIFY:
printf("Window size has changed\n");
break;
}
}
}
If you are new to X11, I personally recommend xcb instead of Xlib because its easier to debug, but its just a personal preference. You could use either or both. Also keep in mind that X11 api has been ported to many languages like python so you are not stuck with C.
Looking through your comments, yes DE/WM can impact your code. Not sure of your use case or how deep you want to go but you can
switch WM (there are a lot to choose from)
Run in a sandbox where no WM is running
See if your WM can white list certain windows so you can modify them directly or see if you WM is scriptable/allows you to add hooks when certain events are run
Write your own WM. You can get notified of every event you care about but you'd have to do everything else you'd ever want so it would be a lot of work
I will admit that X programming can have a bit of a learning curve but it gets better.
Here is a description of my use case:
I have a Windows application that comprised of the main window and it also creates child windows (think of MS Word for instance). What i want to do is draw frames around certain children windows of a given application. Note that when i say window i mean any visible HWND (handle) in the system. This could be a certain window in Excel, or an open pdf document in Abode reader or whatever.
My question is:
Can this be implemented as AN independent API where one would for instance be able to call the following ?
DrawOutline(HWND, OutlineColor, Thikness);
Any pointers as to how to approach this ? Any limitations one might think of? This would not be a plugin to a specific application but a stand alone API. MFC is also OK. Thanx
The Spy++ tool draws frames around any window. Source code for several Spy++ versions is available on the net.
In our project we have three independent applications, and we have to develop a QT control application that controls these three applications. The main window will be seperated to three sub windows - each one display another one application.
I thought to use QX11EmbedWidget and QX11EmbedContainer widgets, but two problems with that:
The QX11Embed* is based on X11 protocol and I dont know if it's supported on non-x11 systems like Windows OS.
Since QT 5 these classes are not existing, and the QT documentation doesn't mention why.
So that I dont know whether to use it or not - I'll be happy to get an answers.
In addition, I see that the QT 5.1 contains QWidget::createWindowContainer(); function that in some posts it looks like this should be the replacement to the X11Embed. Can anyone please explian me more how can I use this function to create a QT widget that will run another application (a Calculator for example) inside its?
I have searched a lot in Google, and didn't find answers to my Qs.
Can anyone please help me? Am I on the right way?
Thanks!
If all three independent applications are written with Qt, and you have their source, you should be able to unify them just through the parenting of GUI objects in Qt.
http://qt-project.org/doc/qt-4.8/objecttrees.html
http://qt-project.org/doc/qt-4.8/widgets-and-layouts.html
http://qt-project.org/doc/qt-4.8/mainwindows-mdi.html
If you don't have access to them in that way, what you are talking about is like 3rd party window management. It is kind of like writing a shell, like Windows Explorer, that manipulates the state and the size of other window applications.
Use a program like Spy++ or AutoIt Spy for Windows and the similar ones for other OS's, and learn the identifying markings of your windows you want to control, like the class, the window title, etc. Or you can launch the exe yourself in a QProcess::startDetached() sort of thing.
http://qt-project.org/doc/qt-5.1/qtcore/qprocess.html#startDetached
Then using the OS dependent calls control the windows. The Qt library doesn't have this stuff built in for third party windows, only for ones under the QApplication that you launched. There are a lot of examples of doing things like this by AutoHotKey, or AHK. It is a scripting language that is made for automating a lot of things in the windows environment, and there is port for Mac as well (though I haven't tried the mac port myself).
So in the end you are looking at finding your window probably with a call like this:
#include <windows.h>
HWND hwnd_1 = ::FindWindow("Window_Class", "Window Name");
LONG retVal = GetWindowLongA(hwnd_1, GWL_STYLE); // to query the state of the window
Then manipulate the position and state of the window like so:
::MoveWindow(hwnd_1, x, y, width, height, TRUE);
::ShowWindow(hwnd_1, SW_SHOWMAXIMIZED);
You can even draw widgets on top of the windows you are controlling if you set your window flags correctly for the windows you are manipulating.
transparent QLabel with a pixmap
Cannot get QSystemTrayIcon to work correctly with activation reason
Some gotchas that come up in Windows when doing all of this, is finding out the quirks of the Windows UI when they set the Display scaling different from what you expect, and if you want to play nice with the Task bar, and handling all the modal windows of your programs you are manipulating.
So overall, it is do-able. Qt will make a nice interface for performing these commands, but in the end you are looking at a lot of work and debugging to get it in a beautiful, reliable, window manager.
Hope that helps.
I never tried it myself, but from the docs in Qt 5.1 I would try QWindow::fromId(WId id), which gives you a QWindow, which should be embeddable with createWindowContainer:
QWindow * QWindow::fromWinId(WId id) [static] Creates a local
representation of a window created by another process or by using
native libraries below Qt.
Given the handle id to a native window, this method creates a QWindow
object which can be used to represent the window when invoking methods
like setParent() and setTransientParent(). This can be used, on
platforms which support it, to embed a window inside a container or to
make a window stick on top of a window created by another process.
But no guarantee. :-)
A bit of background: I'm a C++ programmer mostly, but the only GUI stuff I've ever done was on top of .NET's WinForms platform. I'm completely new to Windows GUI programming, and despite Petzold's excellent book, I'm extremely confused.
Namely, it seems that most every reference on getting started with Win32 is all about drawing lines and curves and things -- a topic about which (at least at present time) I couldn't care less.
I need a checked list box, a splitter, and a textbox -- something that would take less than 10 minutes to do in Winforms land. It has been recommended to me to use the WTL library, which provides an implementation of all three of these controls -- but I keep getting hung up on simple things, such as getting the controls to use the right font, and getting High DPI working correctly. I've spent two days on this, and I can't help but think there has to be a better reference for these kinds of things than I've been able to find. Petzold's book is good, but it hasn't been updated since Windows 95 days, and there's been a LOT changed w.r.t. how applications should be correctly developed since it was published.
I guess what I'm looking for is a modern Petzold book. Where can I find such a resource, if any?
First up, there is virtually no documentation (that I could ever find) explaining how to use WTL. It seems to be a library by experts, for experts.
Your choices then are: Using the MFC app wizard to create an application, or going the Win32 API route. The Win32 API itself is a C API, MFC is a C++ wrapper around the C Win32 API, with the addition of a document-view application model.
However, instead of creating your controls from code: The closest analog the native Windows API has to a "WinForm" is a dialog box. Dialogs are layed out in resource files that are embedded during linking into the EXE or DLL you are developing. The dialog resource takes a font setting that is automatically applied to all controls on the dialog, and dialogs are layed out in terms of dialog units, not pixels, allowing them to automatically scale relative to the font face, and dpi setting on the users system.
If you create a dialog resource, and add it to a simple application, it need look no more complicated than this to get the dialog up onto the screen, and close in response to a click of the OK button.
#include <windows.h>
#include "resource.h"
BOOL CALLBACK MyDialogProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
switch(uMsg){
case WM_INITDIALOG:
return TRUE;
case WM_COMMAND:
switch(LOWORD(wParam){
case IDOK:
EndDialog(hwnd,wParam);
}
return TRUE;
}
return FALSE;
}
int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hNull,LPCTSTR strCmdLine,int nCmdShow)
{
return DialogBoxParam(hInstance,MAKEINTRESOURCE(IDD_DIALOG1),NULL,&DialogProc,0l);
}
There are definitely better ways. For starters, todays Windows apps are expected to have some sophisticated and cool features. If you plan to implement all these from scratch, you'll be spending a lot of time on your project.
Personally, I use MFC. Other choices are valid, but I would really question not using anything library like that at all. Especially when you are running into the types of problems you are.
Can you place these on a dialog box, or are you doing something unusual in a regular window? Normally, most controls are created by plopping them on a dialog designer. No messing with the font required.
Can you step through what you are trying to do and the problems you are seeing?
The Win32 API is aggravatingly hard to use directly, so don't. Most people use some GUI framework. I try to give my personal opinions about more popular choices:
WTL. It is bit too thin layer on Win32 API and has
not been updated much for a decade.
You will face Win32 API itself soon
enough if you try to do something
above simple stock examples with it. Bonus
is that it is extremely quick
compared to competition.
MFC.
Since VS 2008 SP1 MFC is allowing you
to make relatively modern-looking
GUI. If you can live with its strange
coding conventions and heavy macro
usage then it is livable. It is supported by VS IDE but far weaker than WinForms are.
WxWidgets. Initially felt a bit like
MFC that is additionally made
portable. It has become lot better
after people have started to use it
in Python as well.
QT. It is most
flexible and powerful of them.
Unfortunately it has started long
time ago so has some legacy
strangeness in it. It is slow at
places and produces big executables.
Best is to use it as well-isolated
GUI layer and not to mix heavy usage
of STL and boost into that layer.
So I've got an application whose window behavior I would like to behave more like Photoshop CS. In Photoshop CS, the document windows always stay behind the tool windows, but are still top level windows. For MDI child windows, since the document window is actually a child, you can't move it outside of the main window. In CS, though, you can move your image to a different monitor fine, which is a big advantage over docked applications like Visual Studio, and over regular MDI applications.
Anyway, here's my research so far. I've tried to intercept the WM_MOUSEACTIVATE message, and use the DeferWindowPos commands to do my own ordering of the window, and then return MA_NOACTIVATEANDEAT, but that causes the window to not be activated properly, and I believe there are other commands that "activate" a window without calling WM_MOUSEACTIVATE (like SetFocus() I think), so that method probably won't work anyway.
I believe Windows' procedure for "activating" a window is
1. notify the unactivated window with the WM_NCACTIVATE and WM_ACTIVATE messages
2. move the window to the top of the z-order (sending WM_POSCHANGING, WM_POSCHANGED and repaint messages)
3. notify the newly activated window with WM_NCACTIVATE and WM_ACTIVATE messages.
It seems the cleanest way to do it would be to intercept the first WM_ACTIVATE message, and somehow notify Windows that you're going to override their way of doing the z-ordering, and then use the DeferWindowPos commands, but I can't figure out how to do it that way. It seems once Windows sends the WM_ACTIVATE message, it's already going to do the reordering its own way, so any DeferWindowPos commands I use are overridden.
Right now I've got a basic implementation quasy-working that makes the tool windows topmost when the app is activated, but then makes them non-topmost when it's not, but it's very quirky (it sometimes gets on top of other windows like the task manager, whereas Photoshop CS doesn't do that, so I think Photoshop somehow does it differently) and it just seems like there would be a more intuitive way of doing it.
Anyway, does anyone know how Photoshop CS does it, or a better way than using topmost?
I havn't seen anything remarkable about Photoshop CS that requries anything close to this level of hacking that can't instead be done simply by specifying the correct owner window relationships when creating windows. i.e. any window that must be shown above some other window specifies that window as its owner when being created - if you have multiple document windows, each one gets its own set of owned child windows that you can dynamically show and hide as the document window gains and looses activation.
You can try handle WM_WINDOWPOSCHANGING event to prevent overlaping another windows (with pseudo-topmost flag). So you are avoiding all problems with setting/clearing TopMost flag.
public class BaseForm : Form
{
public virtual int TopMostLevel
{
get { return 0; }
}
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool EnumThreadWindows(uint dwThreadId, Win32Callback lpEnumFunc, IntPtr lParam);
/// <summary>
/// Get process window handles sorted by z order from top to bottom.
/// </summary>
public static IEnumerable<IntPtr> GetWindowsSortedByZOrder()
{
List<IntPtr> handles = new List<IntPtr>();
EnumThreadWindows(GetCurrentThreadId(),
(hWnd, lparam) =>
{
handles.Add(hWnd);
return true;
}, IntPtr.Zero);
return handles;
}
protected override void WndProc(ref Message m)
{
if (m.Msg == (int)WindowsMessages.WM_WINDOWPOSCHANGING)
{
//Looking for Window at the bottom of Z-order, but with TopMostLevel > this.TopMostLevel
foreach (IntPtr handle in GetWindowsSortedByZOrder().Reverse())
{
var window = FromHandle(handle) as BaseForm;
if (window != null && this.TopMostLevel < window.TopMostLevel)
{
//changing hwndInsertAfter field in WindowPos structure
if (IntPtr.Size == 4)
{
Marshal.WriteInt32(m.LParam, IntPtr.Size, window.Handle.ToInt32());
}
else if (IntPtr.Size == 8)
{
Marshal.WriteInt64(m.LParam, IntPtr.Size, window.Handle.ToInt64());
}
break;
}
}
}
base.WndProc(ref m);
}
}
public class FormWithLevel1 : BaseForm
{
public override int TopMostLevel
{
get { return 1; }
}
}
So, FormWithLevel1 will be always over any BaseForm. You can add any number of Z-order Levels. Windows on the same level behave as usual, but will be always under Windows with level Current+1 and over Windows with level Current-1.
Not being familiar to Photoshop CS it is bit hard to know exactly what look and feel you are trying to achieve.
But I would have thought if you created a modeless dialog window as you tool window and you made sure it had the WS_POPUP style then the resulting tool window would not be clipped to the main parent window and Windows would automatically manage the z-Order making sure that the tool window stayed on top of the parent window.
And as the tool window dialog is modeless it would not interfere with the main window.
Managing Window Z-Order Like Photoshop CS
You should create the toolwindow with the image as the parent so that windows manage the zorder. There is no need to set WS_POPUP or WS_EX_TOOLWINDOW. Those flags only control the rendering of the window.
Call CreateWindowEx with the hwnd of the image window as the parent.
In reply to Chris and Emmanuel, the problem with using the owner window feature is that a window can only be owned by one other window, and you can't change who owns a window. So if tool windows A and B always need to be on top of document windows C and D, then when doc window C is active, I want it to own windows A and B so that A and B will always be on top of it. But when I activate doc window D, I would have to change ownership of tool windows A and B to D, or else they will go behind window D (since they're owned by window C). However, Windows doesn't allow you to change ownership of a window, so that option isn't available.
For now I've got it working with the topmost feature, but it is a hack at best. I do get some consolation in the fact that GIMP has tried themselves to emulate Photoshop with their version 2.6, but even their implementation occasionally acts quirky, which leads me to believe that their implementation was a hack as well.
Have you tried to make the tool windows topmost when the main window receives focus, and non-topmost when it loses focus? It sounds like you've already started to look at this sort of solution... but much more elaborate.
As a note, it seems to be quite well documented that tool windows exhibit unexpected behavior when it comes to z-ordering. I haven't found anything on MSDN to confirm it, but it could be that Windows manages them specially.
I would imagine they've, since they're not using .NET, rolled their own windowing code over the many years of its existence and it is now, like Amazon's original OBIDOS, so custom to their product that off-the-shelf (aka .NET's MDI support) just aren't going to come close.
I don't like answering without a real answer, but likely you'd have to spend a lot of time and effort to get something similar if Photoshop-like is truly your goal. Is it worth your time? Just remember many programmers over many years and versions have come together to get Photoshop's simple-seeming windowing behavior to work just right and to feel natural to you.
It looks like you're already having to delve pretty deep into Win32 API functions and values to even glimpse at a "solution" and that should be your first red flag. Is it eventually possible? Probably. But depending on your needs and your time and a lot of other factors only you could decide, it may not be practical.