Commits

Anonymous committed 4d10412

Experimental: Clicking an item now switches to the program, if it's already running and the program name is in the window title, except if the control key is held while clicking. TODO: Find the real program name and update the list of windows.

  • Participants
  • Parent commits 16c8ad2
  • Branches switch-to-already-running-programs

Comments (0)

Files changed (3)

 pyRad Changelog
 ===============
 
+- Experimental: Clicking an item now switches to the program, if it's already running and the program name is in the window title, except if the control key is held while clicking. TODO: Find the real program name and update the list of windows. 
+
 pyRad 0.3.3
 
 - FIX: KUniqueApplication: TypeError: keyword arguments are not supported
 - register a global shortcut / gesture in KDE from within the program -> usable as soon as it's installed. -todo
 - make it show faster. -todo
 - add option --only-daemon to only start the daemon without showing the GUI
+- Check if an app is already open. If it is, simply switch to it 
 """
 __ideas__ = """
 ideas:
 - Talk to DBus directly (for higher performance). -> dbus-send --type=method_call --dest=org.kde.pyRad /MainApplication org.kde.KUniqueApplication.newInstance
   (from http://www.staerk.de/thorsten/index.php/Hacking_KDE)
 - Keyboard shortcuts (1, 2, 3, ... for the wheel items -> click paths to programs)
-- Check if an app is already open. If it is, simply switch to it (dbus -> get winID, forceActivateWindow(winID)?). 
-  Sample DBus calls: dbus-send --dest=org.freedesktop.DBus --type=method_call --print-reply / org.freedesktop.DBus.ListNames ; dbus-send --dest=org.kde.konqueror-14040 --type=method_call --print-reply /konqueror/MainWindow_1 org.kde.KMainWindow.winId; dbus-send --dest=org.freedesktop.DBus --type=method_call --print-reply / org.freedesktop.DBus.NameHasOwner string:"org.kde.pyRad"
-  To bring a background app to foreground, hide its main window, then show it again.
-  -> /konqueror com.trolltech.Qt.QWidget.hide + ...show + hide pyRad
+- Show already running programs differently. 
 
 PyPI url: http://pypi.python.org/pypi/pyRadKDE
 """
 from PyKDE4.kdeui import KDialog
 # also the KWindowSystem, so we can get ourselves to the foreground
 from PyKDE4.kdeui import KWindowSystem
+# and NET, which is needed for getting Window Information
+from PyKDE4.kdeui import NET
 
 
 ### Constants ###
         # Setup the circle - TODO: Call it via KUniqueApplication.newInstance
         self.setup()
 
-    def toForeground(self):
-        """Get into the foreground, so the user can click us."""
-        self.activateWindow()
-        KWindowSystem.forceActiveWindow(self.winId())
+    def toForeground(self, winId = None):
+        """Get window into the foreground, so the user can click us.
+	
+	@param winId: Optional ID for the window to get into foreground."""
+	# if we get no other Id, we want to go into the foreground
+	if winId is None: 
+	    self.activateWindow()
+	    winId = self.winId()
+	KWindowSystem.forceActiveWindow(winId)
 
     def setup(self): 
         """Setup the items in the circle - used to show the app anew.
             if self.isInside(pos, i):
                 # If pyRad didn't reach a final action, we stop here.
                 if event.button() == Qt.LeftButton:
-                    if self.labelClicked(i) is None:
-                        break
+		    # if STRG was held when clicking, we want to start a new program under all circumstances
+		    shiftModifierPressed = event.modifiers().__and__(Qt.ShiftModifier) == Qt.ShiftModifier
+		    if shiftModifierPressed: 
+			if self.labelClicked(i, force_new_instance=False) is None:
+			    break
+		    else: 
+			if self.labelClicked(i) is None:
+			    break
                 elif event.button() == Qt.RightButton and i != self.circle[0]:
                     self.editLabel(i)
                     break
         self.save_config(items)
 
 
-    def labelClicked(self, label):
+    def labelClicked(self, label, force_new_instance=True):
         """React to a label being clicked.
-
+	
+	# TODO: When STRG held, always open a new window, otherwise check first, if the program is already open and if yes activate it instead.
+	
         @return: True if the circle reached an end, None if it should continue existing."""
         if label.action is None:
             return True
             self.arrange_in_circle(items)
             # We don't do anything else in that case.
             return None
-        # if it's no folder and not None, we start the program
-        # if this fails, the code ends here
-        # and the circle stays visible.
+        # if it's no folder and not None, we show the program or start a new instance
+        # if this fails, the code ends here and the circle stays visible.
         if label.action is not None:
             try:
-                Popen(split_action(label.action))
-                return True
+		#: The line to call the program
+		program_call = split_action(label.action)
+		# if we want a new instance, we call the program at once (faster than first checking
+		if force_new_instance: 
+		    Popen(program_call)
+		    return True
+		# if the window 
+		#: all currently known windows
+		wins = KWindowSystem.windows()
+		for i in wins: 
+		    # if a window name equals the program to call, get it into the foreground
+		    windowName = unicode(KWindowSystem.windowInfo(i, NET.WMName, NET.WMVisibleName).name())
+		    print windowName
+		    try: 
+			if windowName.split()[-1].lower() == program_call[0].lower(): 
+			    self.toForeground(KWindowSystem.windowInfo(i, NET.WMName, NET.WMVisibleName).win())
+			    return True
+		    except: pass
+		# if no window name fits, start a new program instance
+		Popen(program_call)
+		return True
             except:
                 return None
 
-
-
     def isInside(self, point, thing):
         """Check, if the point is inside the thing."""
         if point.x() > thing.x() and point.x() < thing.x() + thing.width() and point.y() > thing.y() and point.y() < thing.y() + thing.height():